React, Flux, and Immutable data present a perfect match. Since we create a new object for every mutation, it’s very easy to check if an object has changed when compared to an older version of it by just doing a simple reference check. The state in our stores is now immutable, so it’s very easy to determine when our applications state has changed.
Take for instance, a standard Flux implementation. We have a React component that listens to a store which has some state. Let’s take a look at an example UserStore:
On the React side, we will have two components – both listening to same store.
Now, when the UPDATE_ADDRESS action is fired the address in state will be updated, which will trigger the stores change event. When this happens the <UserProfile /> and <Address /> components will be re-rendered.
For simple components this will work just fine. But as the <UserProfile /> and <Address /> components grow in complexity, each re-render can get expensive.
shouldComponentUpdate and Pure Components
Luckily, React allows us to make our components smarter and avoid a re-render by leveraging the shouldComponentUpdate lifecycle event. This event allows us to compare new and current props and state. Implementing this for our <Address /> component will require us to check and compare every property of address to make sure that they all match. As the objects get more complex, these checks also grow in complexity, and they can become tedious and hard to keep up to date.
Compare this to what it would look like when working with immutable data. We could simply do an equality check currentProps.address === newProps.address and that’s it. Since we would create a new version of address whenever it’s updated, a simple reference check will do the trick.
Components designed in this way are called Pure Components. In newer versions of React, there is a PureComponent base class that implements shouldComponentUpdate with a shallow equality check like the one used for address above. The term “Pure” comes from the Functional Programming concept of Pure Functions, where a Pure function is defined as one that always produces the same result given the same input. Similarly, a PureComponent should always render the same element given the same props and state.
Of course, in a simple example like this you could just split up your store and have a ProfileStore and an AddressStore. However, as your application data and UI grow in complexity, this approach can quickly get you in trouble. Trying to match your stores so closely to your React component tree will inevitably force continuous rework on your stores, and it may make your stores much harder to maintain going forward.
How can I leverage immutability in my Flux/React code base?
There are several alternatives for implementing immutable data in your Flux app. The root of immutable data in Flux are your stores and for simple data structures, manually creating a new object on each mutation would do the trick:
For more precise changes, consider using Object.assign or the excellent immutability-helper library. For bigger teams, or for those apps where performance is a big priority, Facebook’s own ImmutableJS is an excellent option.
Implementing immutable data structures in your app may seem unnecessary or adding too much overhead at first. It’s certainly easier to mutate your objects in place, and simple React apps may perform well enough even when re-rendering unnecessarily. However, implementing immutable data structures is a lot easier when it’s part of the initial design, and shortly becomes second nature when writing up a new store. Pure Components become the default option, and as the app grows, performance optimizations will be easier to implement.
Immutable data is an excellent technique that should be part of every React developer’s toolbox. While it may not be necessary for simple use cases, it’s a great asset for developing complex and highly performant React apps.
Using immutable data structures in your app? Why or why not? Leave a comment about your experiences with immutability below.
If you’re interested in learning more about functional programming, check out my post on Functional Programming Principles in React and Flux.