Redux Fundamentals (feat. React)

Mutable State with Immer

Steve Kinney

Steve Kinney

Redux Fundamentals (feat. React)

Check out a free preview of the full Redux Fundamentals (feat. React) course

The "Mutable State with Immer" Lesson is part of the full, Redux Fundamentals (feat. React) course featured in this preview video. Here's what you'd learn in this lesson:

Steve demonstrates how to use Immer to treat immutable objects as mutable without actually mutating the objects. Immer provides a draft version of the specified immutable object for developers to change and figures out how to change the object without mutating state.


Transcript from the "Mutable State with Immer" Lesson

>> One of the things that we saw kind of previously, we're starting to even see it a little bit now if we go into our reducer, right? This isn't even all that bad. But the fact that to change an item, we have to map through all the items, we have to go find the item that we're looking for.

And then we wanna replace all the keys on that item except for the one that we wanted to change. And then we return the new item in the array, in a brand new array, and doesn't feel great. And we saw, I can go back to the slide real quick.

If we go back over to this slide, you can see that as our objects get a little bit more complicated, this can get a little bit out of control. And not only is it tedious, but anything that is tedious is also prone to mistakes, right? Okay, yeah, I'm doing this by hand, it's really annoying.

And all of a sudden you've made a boo-boo, and those the hardest ones to track down. The most common way to debug that is particularly to just throw console logs everywhere and see when it's not the thing that you expected, right? Yeah, we all know about debugger and all those fun things.

We throw console logs everywhere to go looking for it. Luckily, again, that principle of, if something feels tedious, then there might be a better way to do this. There's been a bunch of attempts to add some kind of working with regular mutable JavaScript data types in an immutable fashion, since React kinda needs it, Redux insists on it, so on and so forth.

So one of them is this library called Immer. And the reason that we're gonna talk about Immer is, when we talk about Redux Toolkit, Immer is also kinda built in to Redux Toolkit. So when you see me mutating objects like I don't care anymore, it's not because it's late in the workshop.

It's because I have a library that is kind of helping me treat immutable objects like they're mutable and figuring out the difference for me. And so part of this what we'll do is, it takes a function that will take the object you want to mutate, give you a draft version of it, you can mutate it to your heart's content.

And then it will go figure out how to immutably do all the changes. So you're not typing code like this all the time or worse. So let's look at what that might look like for item added. An item added is pretty simple, but we'll go ahead and we'll say something along the lines of, I'll write a new one that will replace it.

Say action.type === ITEM_ADDED. And Immer comes with a function called produce, right? And produce, in this case, it's gonna take, okay, what is the object that you wanna change immutably in this case or state? And then we'll have a function where you pass in as draft state. And now the version of state in here, you can mutate like you can push things to it, you can just change the property on an object.

All right, for in the case of price and quantity, you can do whatever you want. Then after you're done with this function, Immer is gonna go through and actually figure out how to do all the stuff that we were doing by hand before. That wasn't too bad in this case, but could get a lot worse.

So here I could actually just say, draftState.push(). You can push that item right onto the array, let me grab this one here. And I can basically treat everything in my reducer now. As long as I'm using produce, I can treat it as if I could mutate it. I can do all the much simpler and easier ways to do this.

And I can just get the benefits of it. So I'm gonna do one more, and then I'm gonna do the price this time and you're gonna do the quantity. And we'll see how we can make this code a lot, lot simpler. And then I'll push it up and you'll get a chance to try it out as well.

So, in this case, we will return produce. We'll start with that state, with our draft state. We'll go ahead and we'll find the item. And that's just simply, that's not too bad. That's just gonna be state, go through the array, And find that the item.uuid === action.payload.uuid. And then once we have that item and we found it, we can go through and just say, cool, item.price, just be the new price.

And I can even just point like I'll say, Just in case. But I can now just mutate this object, like it was a regular object. And what will happen is Immer will go ahead and apply all my changes for me. And I can just pretend like mutating objects is totally, totally okay in that sense.

So what I want you to do, let's actually just verify that everything I did works, then what you're gonna do is do the same for quantity, just to kind of get a sense, and then we'll refactor this even better. One of these I wanna do is probably use this draft state to find it instead.

To get the one out of the draft state, otherwise, I will get the immutable one. So just make sure that instead of the state, you're using the draft version. So if you have the Immer version of your array, it will like recursively go down. So you'll have an array of draft items, all the draft properties, so you can just mutate the entire tree.

Let's just verify that that works the way we expect. Right, everything still works, great.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now