IT박스

Angular 2 : 배열의 변화를 감지하는 방법은 무엇입니까?

itboxs 2021. 1. 11. 07:52
반응형

Angular 2 : 배열의 변화를 감지하는 방법은 무엇입니까? (@input 속성)


ajax 요청을 사용하여 객체 배열을 검색하는 부모 구성 요소가 있습니다.

이 구성 요소에는 두 개의 하위 구성 요소가 있습니다. 그 중 하나는 개체를 트리 구조로 표시하고 다른 하나는 내용을 테이블 형식으로 렌더링합니다. 부모는 @input 속성을 통해 배열을 자식에게 전달하고 콘텐츠를 올바르게 표시합니다. 예상대로 모든 것.

개체 내에서 일부 필드를 변경할 때 문제가 발생합니다. 하위 구성 요소에는 이러한 변경 사항이 통지되지 않습니다. 변경 사항은 배열을 해당 변수에 수동으로 재 할당하는 경우에만 트리거됩니다.

저는 Knockout JS로 작업하는 데 익숙하며 observableArrays와 유사한 효과를 얻어야합니다.

DoCheck에 대해 읽었지만 어떻게 작동하는지 잘 모르겠습니다.


OnChanges Lifecycle Hook 은 입력 속성의 인스턴스가 변경 될 때만 트리거됩니다.

입력 배열 내부의 요소가 추가, 이동 또는 제거되었는지 확인하려면 다음과 같이 Lifecycle Hook 내부에서 IterableDiffers 를 사용할 수 있습니다 DoCheck.

constructor(private _iterableDiffers: IterableDiffers) {
    this.iterableDiffer = this._iterableDiffers.find([]).create(null);
}

ngDoCheck() {
    let changes = this.iterableDiffer.diff(this.inputArray);
    if (changes) {
        console.log('Changes detected!');
    }
}

배열 내 객체의 변경 사항을 감지해야하는 경우 모든 요소를 ​​반복 하고 각 요소에 KeyValueDiffers적용해야합니다 . (이전 검사와 병행하여 수행 할 수 있습니다).

자세한 내용은이 게시물을 참조하십시오. Angular2에서 배열 내부의 개체 변경 감지


빈 배열과 병합하여 배열에 대한 새 참조를 언제든지 만들 수 있습니다.

this.yourArray = [{...}, {...}, {...}];
this.yourArray[0].yourModifiedField = "whatever";

this.yourArray = [].concat(this.yourArray);

위의 코드는 배열 참조를 변경하고 하위 구성 요소에서 OnChanges 메커니즘을 트리거합니다.


다음 기사를 읽고 변경 가능한 객체와 변경 불가능한 객체를 놓치지 마세요.

핵심 문제는 배열 요소를 변경하는 반면 배열 참조는 동일하게 유지된다는 것입니다. Angular2 변경 감지는 변경 사항을 감지하기 위해 배열 참조 만 확인합니다. 불변 객체의 개념을 이해하면 문제가있는 이유와 해결 방법을 이해할 수 있습니다.

이런 종류의 문제를 피하기 위해 내 프로젝트 중 하나에서 redux 저장소를 사용합니다.

https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html


IterableDiffers 를 사용할 수 있습니다.

* ngFor 에서 사용됩니다.

constructor(private _differs: IterableDiffers) {}

ngOnChanges(changes: SimpleChanges): void {
  if (!this._differ && value) {
     this._differ = this._differs.find(value).create(this.ngForTrackBy);
  }
}

ngDoCheck(): void {
  if (this._differ) {
    const changes = this._differ.diff(this.ngForOf);
    if (changes) this._applyChanges(changes);
  }
}

이것은 이미 답변 된 것으로 보입니다. 그러나 미래의 문제를 찾는 사람들을 위해 변경 감지 문제를 조사하고 디버깅 할 때 놓친 부분을 추가하고 싶었습니다. 이제 내 문제는 약간 고립되어 있었고 내 입장에서는 어리석은 실수 였지만 그럼에도 불구하고 관련이 있습니다. Array또는 Object참조 에서 값을 업데이트 할 때 올바른 범위에 있는지 확인하십시오. 내가 사용하여 함정에 자신을 설정할 setInterval(myService.function, 1000)경우, myService.function()공공 배열의 값을 업데이트, 나는 서비스를 외부에서 사용. 바인딩이 해제되었으므로 실제로 배열을 업데이트하지 않았으며 올바른 사용법은 setInterval(myService.function.bind(this), 1000). 변경 감지 해킹이 어리 석거나 단순한 실수 였을 때 시간을 낭비했습니다. 변경 감지 솔루션을 시도하기 전에 범인의 범위를 제거하십시오. 시간을 절약 할 수 있습니다.


You can use an impure pipe if you are directly using the array in your components template. (This example is for simple arrays that don't need deep checking)

@Pipe({
  name: 'arrayChangeDetector',
  pure: false
})
export class ArrayChangeDetectorPipe implements PipeTransform {
  private differ: IterableDiffer<any>;

  constructor(iDiff: IterableDiffers) {
    this.differ = iDiff.find([]).create();
  }

  transform(value: any[]): any[] {
    if (this.differ.diff(value)) {
      return [...value];
    }
    return value;
  }
}
<cmp [items]="arrayInput | arrayChangeDetector"></cmp>

For those time travelers among us still hitting array problems here is a reproduction of the issue along with several possible solutions.

https://stackblitz.com/edit/array-value-changes-not-detected-ang-8

Solutions include:

  • NgDoCheck
  • Using a Pipe
  • Using Immutable JS NPM github

It's work for me:

@Component({
  selector: 'my-component',
  templateUrl: './my-component.component.html',
  styleUrls: ['./my-component.component.scss']
})
export class MyComponent implements DoCheck {

  @Input() changeArray: MyClassArray[]= [];
  private differ: IterableDiffers;

  constructor(private differs: IterableDiffers) {
    this.differ = differs;
  }

  ngDoCheck() {
    const changes = this.differ.find(this.insertedTasks);
    if (changes) {
      this.myMethodAfterChange();
  }
}

ReferenceURL : https://stackoverflow.com/questions/42962394/angular-2-how-to-detect-changes-in-an-array-input-property

반응형