Immutable Data with Immer and React setState

Jason Brown
InstructorJason Brown
Share this video with your friends

Social Share Links

Send Tweet

In this lesson we'll show the traditional method of updating state with a spread operator and then transform it into using the Immer produce functionality. This will allow us to achieve immutability on our data with simple mutations We'll then show how Immer can use currying to create updater functions that can be passed directly to setState.

Instructor: [00:00] We'll get started by installing Immer, so we'll have yarn add Immer. Looking at our code, we'll do an import. We'll call the default import from Immer, produce from Immer.

[00:21] Within our application, we have a count that is an object with a subcounter. This is going to display that Immer can update substate the mutations and produce a totally different object much like the spread operator.

[00:38] Let's first take a look at how we would do this with the spread operator. We'll do a componentDidMount and do a set interval. We'll update every 1,000-milliseconds, and then we'll do a setState. Using a spread operator here only makes sense if we have additional state, but because we don't, this will just be an example.

[01:06] Say this.setState. Because we are referencing previous state, we'll need to use a callback function for our setState. Say return, count. We would then spread in state.count and update counter at state.count.counter plus one.

[01:29] If we take a look at this inside of our browser, you can see that's it's updating every single second. However, this can be very cumbersome, especially as the nested objects gets deeper and you want to have immutable state. This is where Immer comes in.

[01:52] We'll first set up one possibility of using Immer and call it const counter. We'll take state and props and then use our produce function. The produce function takes state. We'll additionally take another function and we'll pass in what we call draft which is draft for the next version of this state.

[02:21] One thing that we have being passed in is an increased count from the top level of five, so we'll reference that inside of here to produce the next counter state. With Immer, rather than using a spread operator, we can do a direct mutation. Say draft.count.counter plus equals props.increasecount.

[02:52] If we remove this setState and say const nextState is equal to our counter with this.state and this.props, then we can do this.setState with our next state. If we go look in the browser, we can see that it is increasing by five now.

[03:19] One way to prove that this is actually working is actually comparing the count objects. We can do that with a componentDidUpdate and do a console.log and compare if this.state.count is equivalent to the previous state.count.

[03:36] If we go look in our browser, we can see that it's console logging false. These are indeed different objects even though all we've done is mutate the counter that is nested within it.

[03:49] Furthermore, if we add additional objects to state, so say for example we have a user and we say name. If we compare if this user object has changed -- we can say this.state.user versus the previous state.user -- we can see that they are indeed the same exact object using the triple-equals.

[04:13] Immer is only updating and creating new objects for any time that you mutate an object or value inside of another object. What this means is, that using Immer, you can use strict equality checking to actually prove whether or not a particular component needs to update.

[04:36] One downside currently is that we're using the current state to update the existing state without using a callback function. How we can fix that is actually using the currying functionality within Immer.

[04:52] Rather than passing state as the first argument, if we pass a function, Immer will automatically take whatever the next call, the next value is to produce in the first argument and use that as the state and then proxy all further arguments. Here we can remove this, and then we'll have props be curried further.

[05:23] Rather than calling our counter, we'll just call and pass counter to setState. SetState will then receive this function.

[05:33] The first argument will be state which will be passed into the draft. Then the props is the second argument that setState calls the callback function with which will then be curried and accessed here.

[05:49] Once again, save that. We can go look and see that it is still working and still being increased by five. Also, our username is still not being changed.