Best way to use OnPush change detection
Asked Answered
L

1

6

What is the best way to use OnPush change detection to make flexible in changing and also quite straightforward in testing? Going through various tutorials I have found to approach to use OnPush:

  1. First is to use observable of the subject from service directly in the view I am not sure if that approach is valid. https://blog.angular-university.io/onpush-change-detection-how-it-works/.
  2. Another option is to use immutable.js but in this case, I don't know if that is quite flexible to create Objects, I know that it easier in case of the list.

Maybe you know different approach then this which I listed?

Lovesick answered 24/5, 2018 at 6:31 Comment(0)
R
10
  1. Using Observables with async pipe is a perfectly valid option which I use quite often. Angular is able to check when an Observable emits a value and it marks your component to detect changes.
  2. Immutable.js is as well a valid option, however I personally find a little bit too verbose. On my current project I prefer to use ES6 spread operator. For example to update a property use const newObj = {...obj, prop: newValue}, to insert an item to an array const newArray = [...array, newItem]. However you have to make sure that the whole team adopts this approach as there is no way to enforce the immutability, as with Immutable.js.

My team is using page - component pattern. For example we need to create a feature to update user details. In this case I'd create user-page.component and user-form.component. user-page.component is a container for user-form.component.

user-form.component has ChangeDetectionStrategy.OnPush and it does not interact with the services, it just has a number of input properties (let's say @Input user: User) and emits @Output events (for example @Output update = new EventEmitter<User>()). It is a 'dumb' component which just updates the form and emits events.

user-page.component is the one who interacts with the services, sets input properties and listens for user-form.component events. It's template markup usually only contains child components:

<app-user-form [user]="user$ | async" (update)="onUpdate($event)"></app-user-form>

user$ is an Observable which comes from the service or the store and it is passed into user-form.component through async pipe. onUpdate is function which is called when user clicks Update button on user-form.component and it calls the API service to update the user details.

Following this pattern gives the separation of the components which interacts with the services and the components which only display data, allowing you to have the control of the change detection. By the way NGRX official example app uses the same approach.

Rhodium answered 24/5, 2018 at 8:35 Comment(2)
Great answer, it makes the topic more clear for me, how i is with the testing? I had troubles to test it. when I use onPush detection and async pipes in viewLovesick
if you use the described approach then async pipes should be in page component and OnPush in form component, so they are separate from testing perspective unless you write integration testsRhodium

© 2022 - 2024 — McMap. All rights reserved.