차이점은 무엇이며 ChangeDetectorRef.markForCheck()
그리고 ChangeDetectorRef.detectChanges()
?
나는 두 기능 의 차이점이 아니라에 대한 정보 만 찾았습니다NgZone.run()
.
문서에 대한 참조 만있는 답변에 대해서는 실제 시나리오 중 하나를 선택하는 방법을 설명하십시오.
차이점은 무엇이며 ChangeDetectorRef.markForCheck()
그리고 ChangeDetectorRef.detectChanges()
?
나는 두 기능 의 차이점이 아니라에 대한 정보 만 찾았습니다NgZone.run()
.
문서에 대한 참조 만있는 답변에 대해서는 실제 시나리오 중 하나를 선택하는 방법을 설명하십시오.
답변:
문서에서 :
detectChanges () : 무효
즉, 모델 (클래스) 내부의 항목이 변경되었지만 뷰를 반영하지 않은 경우 Angular에 변경 사항을 감지하고 (로컬 변경 감지) 뷰를 업데이트해야 할 수도 있습니다.
가능한 시나리오는 다음과 같습니다.
1- 변경 감지기가보기에서 분리되었습니다 ( 분리 참조 ).
2- 업데이트가 발생했지만 Angular 영역에 없었으므로 Angular는 이에 대해 알지 못합니다.
타사 기능이 모델을 업데이트하고 그 후에 뷰를 업데이트하려는 경우와 같습니다.
someFunctionThatIsRunByAThirdPartyCode(){
yourModel.text = "new text";
}
이 코드는 Angular 영역 외부에 있기 때문에 변경 사항을 감지하고보기를 업데이트해야합니다.
myFunction(){
someFunctionThatIsRunByAThirdPartyCode();
// Let's detect the changes that above function made to the model which Angular is not aware of.
this.cd.detectChanges();
}
참고 :
위의 작업을 수행하는 다른 방법이 있습니다. 즉, 각도 변경주기 내에 해당 변경을 가져 오는 다른 방법이 있습니다.
** zone.run 내부에서 해당 타사 기능을 래핑 할 수 있습니다.
myFunction(){
this.zone.run(this.someFunctionThatIsRunByAThirdPartyCode);
}
** setTimeout 안에 함수를 래핑 할 수 있습니다.
myFunction(){
setTimeout(this.someFunctionThatIsRunByAThirdPartyCode,0);
}
3- change detection cycle
완료 후 모델을 업데이트 하는 경우도 있습니다.이 경우이 두려운 오류가 발생합니다.
"확인 된 후 표현이 변경되었습니다";
이것은 일반적으로 (Angular2 언어에서) 의미합니다.
허용 된 방법 중 하나 (이벤트, XHR 요청, setTimeout 및 ...)로 인한 모델 변경을보고 변경 감지를 실행하여보기를 업데이트하고 완료했지만 다른 것이있었습니다. 코드에서 함수를 다시 업데이트하여 모델을 다시 업데이트했으며 AngularJS와 같은 더티 검사가 더 이상 없기 때문에 변경 감지를 다시 실행하고 싶지 않습니다. 우리는 단방향 데이터 흐름을 사용해야합니다!
이 오류가 분명히 나타납니다. : P
그것을 고치는 몇 가지 방법 :
1- 올바른 방법 : 업데이트가 변경 감지주기 내에 있는지 확인하십시오 (Angular2 업데이트는 한 번만 발생하는 한 가지 흐름이며, 그 후에 모델을 업데이트하지 말고 코드를 더 나은 장소 / 시간으로 이동하십시오).
2- 게으른 방법 : angular2를 행복하게하기 위해 업데이트 후 detectChanges ()를 실행하십시오. 이것은 가장 좋은 방법은 아니지만 가능한 시나리오가 무엇인지 물었을 때, 그중 하나입니다.
당신이 말하는 방식 : 진심으로 변경 감지를 실행했음을 알고 있지만 확인을 마친 후에 즉시 업데이트해야하기 때문에 다시 수행하고 싶습니다.
3- 영역에 의해 패치되고 완료된 후에 실행 setTimeout
되므로 코드를에 넣 습니다.setTimeout
detectChanges
문서에서
markForCheck() : void
이것은 구성 요소 의 ChangeDetectionStrategy 가 OnPush 인 경우에 주로 필요 합니다 .
OnPush 자체는 다음 중 하나가 발생한 경우에만 변경 감지를 실행 함을 의미합니다.
1- 컴포넌트의 @input 중 하나가 완전히 새로운 값으로 바뀌 었거나 @Input 속성의 참조가 완전히 바뀌었을 경우 간단히 넣습니다.
따라서 구성 요소의 ChangeDetectionStrategy 가 OnPush 이고 다음이있는 경우
var obj = {
name:'Milad'
};
그런 다음 다음과 같이 업데이트 / 변경하십시오.
obj.name = "a new name";
이것은 obj 참조를 업데이트하지 않으므로 변경 감지가 실행되지 않으므로보기가 업데이트 / 변경을 반영하지 않습니다.
이 경우 뷰를 확인하고 업데이트하도록 수동으로 Angular에 지시해야합니다 (markForCheck).
그래서 당신이 이것을했다면 :
obj.name = "a new name";
이 작업을 수행해야합니다.
this.cd.markForCheck();
오히려 아래에서 변경 감지가 실행됩니다.
obj = {
name:"a new name"
};
이전 obj를 완전히 새로운 것으로 대체했습니다 {}
.
2- 클릭과 같은 이벤트가 발생했거나 하위 구성 요소가 이벤트를 생성했습니다.
같은 이벤트 :
간단히 말해서 :
detectChanges()
각도가 변경 감지를 실행 한 후 또는 업데이트가 각도 세계에 전혀없는 경우 모델을 업데이트 한 경우 사용 합니다.
사용 markForCheck()
당신은 인 OnPush를 사용하고 당신은을 우회하는 경우 ChangeDetectionStrategy
일부 데이터를 돌연변이에 의해 또는 당신은 내부의 모델을 업데이트했습니다 에서는 setTimeout을 ;
detectChanges
업데이트보기. 이 자세한 설명을 참조하십시오 .
this.cdMode === ChangeDetectorStatus.Checked
, 뷰를 업데이트하지 않을 것이므로 markForCheck를 사용하는 것입니다.
detectChanges
. 그리고 cdMode
Angular 에는 없습니다 4.x.x
. 나는 내 기사에 그것에 대해 씁니다. 네가 좋다 니 기쁘다. 당신이 매체에 그것을 추천하거나 나를 따라갈 수 있다는 것을 잊지 마십시오 :)
이 둘의 가장 큰 차이점은 detectChanges()
실제로 변경 감지를 트리거하지만 변경 감지 markForCheck()
는 트리거하지 않는다는 것입니다.
이것은 트리거하는 구성 요소로 시작하는 구성 요소 트리에 대한 변경 감지를 실행하는 데 사용됩니다 detectChanges()
. 따라서 변경 감지는 현재 구성 요소 및 모든 하위 구성 요소에 대해 실행됩니다. Angular는 루트 구성 요소 트리에 대한 참조를 보유 ApplicationRef
하며 비동기 작업이 발생하면 래퍼 메서드를 통해이 루트 구성 요소에 대한 변경 감지를 트리거합니다 tick()
.
@Injectable()
export class ApplicationRef_ extends ApplicationRef {
...
tick(): void {
if (this._runningTick) {
throw new Error('ApplicationRef.tick is called recursively');
}
const scope = ApplicationRef_._tickScope();
try {
this._runningTick = true;
this._views.forEach((view) => view.detectChanges()); <------------------
view
여기에 루트 컴포넌트 뷰가 있습니다. 여러 구성 요소 부트 스트랩의 의미 는 무엇입니까? 에서 설명한 것처럼 많은 루트 구성 요소가있을 수 있습니다 .
@milad는 변경 감지를 수동으로 트리거해야하는 이유를 설명했습니다.
내가 말했듯이,이 사람은 변경 감지를 전혀 트리거하지 않습니다. 단순히 현재 구성 요소에서 루트 구성 요소로 올라가고 뷰 상태를로 업데이트합니다 ChecksEnabled
. 소스 코드는 다음과 같습니다.
export function markParentViewsForCheck(view: ViewData) {
let currView: ViewData|null = view;
while (currView) {
if (currView.def.flags & ViewFlags.OnPush) {
currView.state |= ViewState.ChecksEnabled; <-----------------
}
currView = currView.viewContainerParent || currView.parent;
}
}
구성 요소에 대한 실제 변경 감지는 예약되지 않았지만 향후 (현재 또는 다음 CD주기의 일부로) 발생할 경우 변경 감지기를 분리 한 경우에도 상위 구성 요소보기를 검사합니다. 변경 탐지 전략 을 사용 cd.detach()
하거나 지정 하여 변경 탐지기를 분리 할 수 있습니다 OnPush
. 모든 기본 이벤트 핸들러는 모든 상위 구성 요소보기를 확인 표시합니다.
이 접근 방식은 종종 ngDoCheck
수명주기 후크 에서 사용됩니다 . 당신은 더 많은 읽을 수 있습니다 당신이 생각하는 경우 ngDoCheck
구성 요소가 선택되는 방법을 -이 기사를 읽어 .
자세한 내용은 Angular의 변경 감지에 대해 알아야 할 모든 항목 을 참조하십시오.
markForCheck
입니다. 따라서 비동기 파이프를 사용하지 않는다면 아마도 이것이 사용되어야 할 것입니다. 그러나 변경 사항 감지를 시작하기위한 일부 비동기 이벤트의 결과로 상점 업데이트가 발생해야합니다. 그것은 항상 그렇습니다. 그러나 예외가 blog.angularindepth.com/...
async pipe
(가) 우리가 일반적으로 같이 할 수있는 몇 가지를 구독 내부에 있기 때문에 call setFromValues
do some comparison
.. 그리고 만약 async
자체가 호출 markForCheck
우리가 자신을 호출하면 무슨 문제가? 그러나 다시 우리는 ngOnInit
다른 데이터 를 얻는 데 보통 2-3 개 이상의 선택자가 markForCheck
있고 모든 것을 호출 합니다. 괜찮습니까?
cd.detectChanges()
현재 구성 요소에서 하위 구성 요소를 통해 즉시 변경 감지를 실행합니다.
cd.markForCheck()
변경 감지는 실행하지 않지만 조상은 변경 감지를 실행해야한다고 표시합니다. 다음 번에 변경 감지가 실행되면 표시된 구성 요소에 대해서도 실행됩니다.
cd.markForCheck()
. 종종 변경 사항이 여러 구성 요소에 영향을 미치며 변경 감지가 호출됩니다. 당신은 기본적으로 말을하는지 : 그냥 확인이 구성 요소가되어 있는지 확인하자 또한 그렇게되면 업데이트되었습니다. (보기는 내가 작성한 모든 프로젝트에서 즉시 업데이트되지만 모든 단위 테스트에서는 업데이트되지 않습니다).cd.detectChanges()
되지 않고 현재 실행 변경 감지, 사용 cd.markForCheck()
. detectChanges()
이 경우 오류가 발생합니다. 이것은 아마도 Angular의 변경 감지가 설계되었다는 가정에 반하는 조상 구성 요소의 상태를 편집하려고 함을 의미합니다.detectChanges()
. markForCheck()
실제로 시간에 맞게보기를 업데이트하지 못할 수 있습니다. 예를 들어, 단위 테스트는보기에 영향을 미치므로 fixture.detectChanges()
앱 자체에서 필요하지 않은 경우 수동으로 호출해야 할 수 있습니다 .detectChanges()
변경하는 경우 구성 요소의 상위 항목에서 불필요하게 변경 감지를 실행하지 않기 때문에 성능을 향상시킬 수 있습니다.