During this year’s Reactathon one of the coolest presentation I had to chance to catch was with Mark Erickson. He was there to present some modern Redux techniques and specifically the React Toolkit and the use of the ever popular *hooks*. It inspired me to go back and refactor some of my old Redux code from using the ‘connect’ higher order component to using the Toolkit. So if you’re looking to refactor Redux to make use of it’s hooks I’m gonna walk through a simple refactor and implementation of Redux Toolkit.
First things first I’ll start with a basic React app that has some built in Redux ‘connect’ functionality built into it. For the purposes of this demo it will be a simple store app with an item counter. Below is the basic setup of the three main files that hold Redux functionality. The Reducer, Index.js (where I’m creating my store for the purposes of this demo), and App.js (which is connected to the store’s state and dispatch through it’s props):
So here we have everything set up. Our App component is subscribed to our Redux store and it’s single piece of state (itemCount) and has it’s single dispatch method to increase the count of itemCount. Its a superrrr simple set up and normally on a larger scaled app you would see an action’s file that held all the different dispatch functions so they could be reused across components but this is fine for a simple demo.
So where do we begin on refactoring our code to make use of Redux Toolkit and then React-Redux hooks? Well, installing it would probably a good idea.
npm install --save @reduxjs/toolkit
This will install the toolkit which has a few tools conveniently bundled together. This does Not include however React-Redux which you will still need to install if you plan to be using Redux’s hooks (useSelector, useDispatch) but more on that a little later. It also comes with immer, thunk and reselect all of which are useful and will be important to how React Toolkit functions on a larger scale. But we’ll come back to those as well a little later. For now let’s just start with refactoring some of our existing code.
First we’ll go ahead and add a store.js file to our Redux folder. We’re going to move the creation of our store away from index.js and into this file now. Using the Redux Toolkit method configureStore we can import our storeReducer and export to our index.js a fully configured store. If we were to have multiple reducers this would also be where we can combine them (think combineReducers). Below is the refactored code, be sure to note the changes in imports. In store.js we’re now importing from @reduxjs/toolkit.
Now that we have those two changes done we’ll move on to the real magic, which is going to be in our storeReducer. Here we will utilize my favorite Redux Toolkit method ‘createSlice’. This will essentially combine our Reducer and Actions all together into a ‘slice’ of state. First off, just for sake of clarity I’ll rename the reducer file storeSlice.js and then fix our import from the store.js file. Next, we will start by declaring a new slice using createSlice. We will then configure it with a few things using key/value pairs starting with “name” which will will stick with ‘store’. Next, we will also define its initial state, which for us only includes our itemCount set to zero initially. After the initialState we define our reducers which upon export Redux Toolkit will turn into dispatch actions we can use throughout our application. Ultimately, it should looks something like this and I’ve left the previous Reducer code for reference commented out on the right.
Above you can also see we are exporting ‘increaseCount’ as an action of storeSlice. This is the dispatch method that we will ultimately call within our App component. This now leaves one last export that we’re missing which deals with subscribing to state. Now that we are refactoring away from the ‘connect’ method and not mapping our state/dispatch to props, we will be using the hook ‘useSelector’. We therefore need to export our piece of state (itemCount) right before we export our storeSlice.reducer. Our final storeSlice should ultimately look like this:
State.store.itemCount points to our slice that we named ‘store’ and then within our initialState the itemCount which we set to zero. selectItemCount is of course a conventional naming of the export and you could name it whatever you like. Now finally on to our last refactor which will happen within our App component!
First thing we can do is go ahead and delete all our mapState and mapDispatch code. ‘Un-connect’ our App component and change all our imports so that we now import the two hooks we will need (useSelector & useDispatch) from react-redux. Then we will also import our specific piece of state and our action from our storeSlice (selectItemCount & increaseCount).
The final step is to then utilize them within the component. We declare a variable using ‘useSelector’ which will subscribe our component to that piece of the redux store. We also then declare our dispatch by calling the hook within the component. We then only need to call the dispatch method ‘increaseCount’ onClick of our App button!
Of course if you’re looking to take a deeper dive into the functionality of Redux Toolkit and what’s happening ‘under the hood’, the docs provided on their official site are an incredible resource.