Using Immutable Objects

Modeling application state using immutable objects solves these problems. If both person and address are immutable, we can tell a lot more about when the DisplayPerson component can change. The component can change if and only if any of its inputs changes. And we can communicate it to Angular by setting the change detection strategy to OnPush.

Using this change-detection strategy restricts when Angular has to check for updates from “any time something might change” to “only when this component’s inputs have changed”. As a result, the framework can be a lot more efficient about detecting changes in DisplayPerson. If no inputs change, no need to check the component’s template. Perfect! Immutable objects are awesome!

How to Use Immutable Objects in JS

Primitives types like strings and numbers are immutable. You can freeze JavaScript objects and array to make them immutable, but a better option would be to use libraries like Immutable.js or Mori. They provide efficient implementation of immutable collections and records and are easy to use.

As usual, there are trade-offs.

Modeling application state using exclusively immutable objects requires pushing the state management out of the component tree. Think about it. Since address is immutable, we cannot update its street property in place. Instead, we have to create a new address object. Say this address is stored in some PersonRecord object. Since that object is immutable too, we will have to create a new PersonRecord object. Therefore, the whole application state will have to be updated if we change the street property of the address.

There are many ways to organize the application state, but for simplicity let’s assume it is stored in a single data structure. Although it may look scary at first, this setup actually provides a lot of benefits: we can serialize the state of the whole application, inspect it, etc.

So we decided to remove all local mutable state from our components. But since the state is there for a reason, we cannot just remove it — we need to move it somewhere. The only place to move it to is the application state object. This means that some state that previously would have been encapsulated, becomes public. Let’s look at an example illustrating this.

Say we have a typeahead component that we can use like this:

And this is a sketch of the component’s class:

This is just the public interface of this component. In practice, the typeahead component will have a lot more going on. For example, it might store some scrolling position, which can only be updated by events triggered in typeahead.html:

The scrolling position is internal to typeahead. No client of the component has to know the property is even there.

Completely disallowing local mutable state will mean that the scrolling position will have to be stored in the application state object. Suddenly, the client now has to know that the scrolling position is there. We need to pass it in and out. This isn’t ideal from the dev ergonomics standpoint. But what is even more important, it makes the component less reusable.

In summary, removing mutable state simplifies tracking changes in the application and makes the application more performant. But at the same time it breaks the encapsulation of components, and their implementation details start to leak out.