我将从我在StackOverflow上看到过类似问题的想法开始这个问题,但是该问题只能解决差异。

我要问的是,我应该根据情况使用什么,一种或另一种方法可能具有的缺点。

我知道detectChanges在元素及其子元素上立即执行更改检测周期,而markForCheck仅将当前元素及其祖先标记为脏,并且应在下一个更改检测周期中对其进行检查。

我之所以这样问,主要是因为我不认为我应该始终在异步调用中使用markForCheck

例如,我有一个InputComponent,它是常规HTML输入的包装器。此InputComponent已启用ChangeDetectionStrategy.OnPush

当我对服务器进行异步调用并获取数据时,我需要在该InputComponent上运行更改检测以更新选项列表,对此我有两个选项。

首先(我觉得我应该使用的)是detectChanges,因为它将仅对此确切的组件应用检查,而markForCheck将导致对整个 Twig 进行检查。

那么,我应该使用什么?我需要使用markForCheck吗?为什么?

最佳答案



您应该永远不要调用detectChanges()
detectChanges()没有为开发人员提供值(value)的优势。它通常用在程序员无法很好地管理其不变性,状态管理和组件变更的项目内部。

所有需要detectChanges()的源代码都可以重写,因此不是必需的。

另一方面,markForCheck()确实有应使用的边缘情况。



您经常会在调用this的源代码附近找到对markForCheck()的引用。

@Component({...})
export class ExampleComponent {
    //......
    public function work() {
        this.httpClient.get(...).subscribe(resp =>
            this.data = resp.data;
            this.changeDetectorRef.markForCheck();
        });
    }
}

在函数式编程中,对this的引用是不纯的,并且会使函数范围之外的外部状态发生变化。脱离函数式编程最佳实践的做法引入了一些问题,需要对其进行修复才能使一切正常运行。如果您仅使用异步操作编写纯函数,则无需调用markForCheck(),但是一旦引入了this引用,组件状态就会发生变化,并且需要通知 View 。

上面没有任何问题,但是与此同时,RxJS订阅中对this的过度使用产生了难以维护的源代码。

最好重写源代码以使用响应式(Reactive)编程,并在模板中使用async管道。关键是要创建无状态的组件,从而无需更新组件上的属性。一切都作为 react 流完成。

@Component({
    template: `<ng-container *ngIf="data$ | async as data">
               <!-- stuff -->
               </ng-container>`,
    // .....
})
export class ExampleComponent {
    public data$: Observable<any>;

    public function work() {
        this.data$ = this.httpClient.get(...).pipe(shareReplay(1));
    }
}

如果您将组件设计为无状态,并使用RxJS进行所有数据处理,那么就不需要使用markForCheck()了。即使您监听DOM事件,也可以将数据通过管道传输到其他可观察对象,以避免使用this

虽然有时您必须调用markForCheck()。我建议您停止并重新思考避免使用该方法的方法,因为应该有另一种不需要它的方法。

10-08 04:14