Redux Toolkit (Immer & Thunk)

Brian Lego
JavaScript in Plain English
6 min readJan 2, 2021

--

In my last post I did a short walk through of refactoring existing Redux code to utilize the Redux Toolkit and React-Redux Hooks. That article can be found (here) and seeing as I will be adding on to the demo started there it may be a good place to start. Now, two additional bits of Redux Toolkit functionality I wanted to touch on deal with directly mutating state within our slice (thanks to Immer) and then also making asynchronous HTTP calls (thanks to Thunk). So stick around and I’ll walk you through the process of adding these functionalities to our previous demo.

Let’s start with just a quick look at our previous code.

Store (left), Slice(center), App Component(right)

We have our basic store setup, our Slice with some simple state that our App Component is subscribed to and a dispatch method that will increase the ‘itemCount’ within our state.

Adding <form> to App.js

Let’s dive straight in with some changes to our App component. I’ll start off by now incorporating actual item objects into our application. It will have a simple form that our users will fill out to create a new item and add it to their cart. Leaving the onSubmit blank, we’ll come back to it in a moment once we’ve written our dispatch method that will add it to our state within Redux. Next we need to go to our storeSlice.

Seeing as we’ll be working with an array of actual items, our itemCount becomes a redundant so we will just go ahead and swap it for an array we’ll call items. Therefore we can also get ride of the increaseCount() we had within our reducers and our exported selectItemCount as well. We’re going to replace all of these with functionality for an array, which our App component will then subscribe to and be able to determine the item count from the length of the array. The refactor should result in a storeSlice that looks like this:

Refactored storeSlice for items: []

So with these new changes, we have set up our Slice to utilize Immer. Previously in Redux, best practices stated that changes to state had to be made without directly mutating state, ie creating a copy of the current state, manipulating that copy and then reassigning to state to your mutated copy. Immer does all of this behind the scenes for you. Their docs describe it like this:

“The basic idea is that you will apply all your changes to a temporary draftState, which is a proxy of the currentState. Once all your mutations are completed, Immer will produce the nextState based on the mutations to the draft state. This means that you can interact with your data by simply modifying it while keeping all the benefits of immutable data.”

“Using Immer is like having a personal assistant; he takes a letter (the current state) and gives you a copy (draft) to jot changes onto. Once you are done, the assistant will take your draft and produce the real immutable, final letter for you (the next state).”

What it means for us is a super simple way to work with and mutate our Redux state. We can directly push into the ‘items’ array and let Immer do a bunch of work behind the scenes for us. With this done we’ll go ahead and make some more changes to our App Component which can now reflect our changed Slice.

Refactored App component

We start off fixing our imports from the storeSlice to addItem(our dispatch method) and selectItem(our piece of state that we are subscribed to). We now simply add a submit handler for our form which will send our user created item to our Redux store. There Immer will take care of mutating our state appropriately and once the item is added to our items array it will be reflected in our items count show on line 26. This is but a small example of how we can mutate and change state within our Redux Toolkit with the help of Immer.

Next lets go back to our storeSlice where we can implement a GET request to a dummy API which would theoretically populate our items array on initial load of our application. This can all be done right within our storeSlice using the Thunk middleware built into Redux Toolkit to make asynchronous calls to an outside source(usually a database). There are of course other middleware options you could use for making asynchronous calls but Thunk comes ‘out-of-the-box’ with Redux Toolkit and with it’s ease-of-use, it’s a great place to start for writing async calls within Redux.

storeSlice.js w/Async Fetch Call

So, within our storeSlice we add two things, first a ‘fetchAll’ reducer action that will set our items array to whatever is returned from the fetch call. For the purposes of this demo we are assuming that our fetch call will just return an array of items from our DB. Second we add the actual fetch call ‘itemsFetch’ which we pass in our dispatch, and with the help of Thunk behind the scenes, makes an asynchronous call for us. We then of course parse our returned data and subsequently call our fetchAll() reducer method to assign our items array with the data we just received.

Fairly simple and a lot cleaner than previously writing Redux async calls and corresponding reducer methods. Now we simply need to use or itemsFetch method within our App component utilizing the useEffect hook and were all set up to make an initial async fetch call (using Thunk), through our Redux Toolkit which can directly mutate state (using Immer). Simple as that. Below are our final App Component and StoreSlice files.

Final App.js (left) & storeSlice.js (right)

So there you have two small examples of how you can continue to build out your Redux functionality. This is again, just scratching the surface as I’m sure you can imagine you could easily build this up and scale it to a fully fleshed out application. This was to hopefully just give you a taste of how easy writing previously complicated and often times convoluted Redux code can be simplified using the Redux Toolkit.

Of course if you’re looking for a further dive into it’s functionality the docs for Redux Toolkit, Immer and Thunk are all listed below and have some more great examples and use cases!

--

--