Angular markForCheck vs detectChanges

落花浮王杯 提交于 2021-02-18 12:13:27

问题


I'll start this question from notion that I've seen a similar question on StackOverflow, but that question had only answer for the difference.

What I'm asking is what should I use depending on situation and what drawbacks one or another method may have.

I know that detectChanges runs immediate change detection cycle on an element and its children, meanwhile markForCheck only marks current element and its ancestors as dirty and that they should be checked on the next change detection cycle.

I'm asking this mostly because I don't feel like I should always use markForCheck in async calls.

For example I have an InputComponent which is a wrapper for a regular HTML input. This InputComponent has ChangeDetectionStrategy.OnPush enabled.

When I make an asynchronous call to the server and get the data I need to run the change detection on that InputComponent to update a list of options and I have two options for that.

First (what I feel I should be using) is detectChanges because it would apply checks only for this exact component, whilst markForCheck would cause the whole tree branch to be checked.

So what should I use and do I need to use markForCheck ever and why?


回答1:


What I'm asking is what should I use depending on situation and what drawbacks one or another method may have.

You should never call detectChanges().

There isn't a good edge case where detectChanges() offers value to the developer. It's usually used inside projects where immutability, state management and mutation of the component have not been well managed by the programmer.

All source code that needs detectChanges() can be rewritten so that it's not required.

On the other hand, markForCheck() does have good edge cases where it should be used.

I'm asking this mostly because I don't feel like I should always use markForCheck in async calls.

You will often find a reference to this near source code that calls markForCheck().

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

In functional programming, a reference to this is impure and mutates an external state outside the scope of the function. Breaking from functional programming best practices introduces problems that require fixes to keep everything working. If you write only pure functions with your async operations you never have to call markForCheck(), but once you introduce a this reference the components state is mutated and the view needs to be notified.

There is nothing wrong with the above, but at the sametime excessive usage of this in RxJS subscriptions creates source code that can be difficult to maintain.

It's better to rewrite your source code to use reactive programming, and use the async pipe in the template. The key is to create components that are stateless so that a properties on the component don't need to be updated. Everything is done as a reactive stream.

@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));
    }
}

If you design your components to be stateless and use RxJS for all of your data processing, then there shouldn't be a requirement to use markForCheck(). Even when you listen for DOM events the data can be piped to other observables to avoid using this.

While there will be times when you have to call markForCheck(). I recommend that you stop and rethink your approach to avoid the use of it, because there should be another way that doesn't require it.



来源:https://stackoverflow.com/questions/57380682/angular-markforcheck-vs-detectchanges

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!