Angular OnPush Change Detection Strategy: An Illustrated Guide

Master Angular’s OnPush change detection strategy with this illustrated guide.

Ah, change detection — the “magic” that makes Angular applications tick, literally.

For those unfamiliar with the term, it is the process through which Angular detects changes. (duh)

You know… checking to see whether the application state has changed, and if any DOM needs to be updated.

There are two ways this can happen, which are called strategies:

  • the Default strategy, and

  • the OnPush strategy.

In this article, we will study the two change detection strategies of Angular. We will use illustrations to explain how these two work. By the end of this article, you will know how the OnPush strategy works in many different scenarios.

Let’s get started!

Symbols & Their Meaning

This guide contains several illustrations with symbols. So, before we dive into the actual topic, let’s first introduce the symbols and their meaning.

In an Angular application, components form a tree hierarchy, known as the component tree. Each component is a node of that tree.

We will depict a component node based on which strategy it uses as follows:

Component tree node using the Default strategy (left) and the OnPush strategy (right)

Next, we will depict a node dispatching an event (event binding, output binding, or @HostListener), running change detection, or receiving an input (through template binding) as follows:

Component tree node dispatching an event (left), running change detection (middle), receiving an input (right)

That’s everything we are going to use. Pretty simple, right?

Well, you can always come back for a quick peek, should you need a refresher.

Now, let’s get to the fun part!

The Default Strategy

Zone.js is a signaling mechanism that Angular relies on to perform change detection.

But, Zone.js doesn’t provide accurate information about what changed and where. It only tells Angular that one or more components changed in the component tree.

Angular has to then run change detection top-down the component tree to figure out where and what exactly changed.

The default strategy is to run change detection — from top to bottom — for all components in the tree, as seen below.

The OnPush Strategy

We can reduce the number of components on which Angular has to run change detection by using the OnPush strategy.

The OnPush strategy instructs Angular to run change detection for a component subtree only when:

  1. The root component of the subtree receives new inputs as the result of a template binding.

  2. Angular handles an event (event binding, output binding, or @HostListener) in the subtree’s root component or any of its children whether they are using OnPush change detection or not.

We will use (1) and (2) to refer to these rules in the examples that follow. Let’s examine a few different scenarios to better understand how the OnPush strategy works.

In our first scenario, an OnPush node receives a new input. Nodes C and E are OnPush and C receives a new input.

Change detection will run on all components except E, because:

  • A, B, and D use the Default strategy

  • C uses OnPush, but the rule (1) applies (it received a new input)

  • E uses OnPush, but it didn’t receive any new inputs, hence it’s not checked

  • F is part of the subtree with C as its root and uses the Default strategy, hence it is checked

In our next scenario, the event happens on a component that uses the OnPush strategy. Nodes C and E are OnPush and the event occurs on C.

Change detection will run on all components except E, because:

  • A, B, and D use the Default strategy

  • C uses OnPush, but rule (2) applies (the event is in its scope)

  • E uses OnPush, but the event is out of its scope, hence it’s not checked

  • F is part of the subtree with C as its root and uses the Default strategy, hence it is checked

In our third scenario, the event happens on the child of a component that uses the OnPush strategy. Nodes B and D are OnPush and the event happens on D.

Change detection will run on all components, because:

  • A, C, E, and F use the Default strategy

  • B uses the OnPush strategy, but the event happened on D which is its child, hence rule (2) applies

  • D uses the OnPush strategy, but the rule (2) applies (the event is in its scope)

In our last scenario, the event happens on a component that uses the Default strategy. Nodes C and E are OnPush but the event occurs on D.

Change detection will run only on A, B, and D, because:

  • A, B, and D use the Default strategy

  • C uses OnPush and none of the rules holds, hence the entire subtree is skipped

Conclusions

Angular has two change detection strategies — Default and OnPush.

The Default is to run change detection on all components. But we can improve performance by using the OnPush strategy and skipping components or entire subtrees that don’t need to be checked.

We’ve covered all the basic scenarios for the OnPush strategy. Mastering these will help you understand how the strategy works in every other scenario.

That’s all for now!

Thank you for reading!