Making a React To-Do List With Redux Toolkit in TypeScript

Today we will learn how to make a To-Do list using Redux to manage our app's state.

Brian Francis
JavaScript in Plain English

--

Redux is a popular state-management library, especially with React, but one of the downsides/complaints about Redux is often how boiler-platey it can be. Enter Redux Toolkit. Redux Toolkit cuts down significantly on the amount of Redux code that we will have to write and greatly improves developer experience, as you are about to see. So without further ado, let’s dive into creating our To-Do list.

Prerequisites

  • React Knowledge
  • TypeScript Knowledge
  • JavaScript Knowledge
  • Understanding of how Redux works (this will help, but is not necessary)

Let’s Get Started

Before we do anything else, our first step will be to create our project. We will be using one of the create-react-app templates as a starter for this project. Running the following command will generate a starter project which we will be using.

There is a template for redux-typescript, but we would have to delete most of the files and code for this project anyway.

Project Setup

npx create-react-app redux-todo-list --template typescript

After your project is built, you can go ahead and open it up in the code editor of your choice. I will be using VS Code, but you can use whatever you feel comfortable using.

With our project opened up, it’s time to trim some unnecessary files from the src folder:

  • App.test.tsx
  • App.css
  • index.css
  • logo.svg
  • setupTests.ts
  • reportWebVitals.ts

Our src folder should look something like this when we are done.

With all of the unnecessary files and folders deleted, it is time to clean out the App.tsx and index.tsx files. It should look like the below code.

The last thing we will need to do to set up our project is to install a few packages. Running the following command will install the packages that we will need for our app.

npm install @reduxjs/toolkit react-redux @material-ui/core @material-ui/icons uuid @types/uuid

Or if you are using yarn.

yarn add @reduxjs/toolkit react-redux @material-ui/core @material-ui/icons uuid @types/uuid

Description of the packages

We will be using @material-ui/icons and @material-ui/core to style our app, uuid to generate unique ids, @reduxjs/toolkit is responsible for our state management, and react-redux will be used to provide our state to the React application.

Make sure our app runs

Go ahead and run the following command to make sure that our app is good to go.

npm start

Or if you are using yarn.

yarn start

Let’s Start Coding

Creating a To-Do Type

With our project structured the way we need it to be, it is time to write some code. I want to start by creating a model for how our To-Do list is going to be structured. Let’s start by creating a new folder in our src folder and calling it models. Let’s create a file in our models' folder that is called Todo.ts. It should look like this.

Setting Up Redux in the App

With our interface now created for our Todo, it is time to set up our Redux store and what Redux Toolkit calls a “slice.” We can go ahead and create a new folder in our src folder called redux. Next, let’s add a file to our redux folder called todoSlice.ts. This will control how our state management for our app works and is going to look like this.

An explanation of the above code:

Let’s start by talking about line 5 of the above example. This is fairly self-explanatory, but we will need to set what the state is at the start of our application (in this case, an empty array of type Todo). When we get down to line 7, we will see Redux Toolkit in action for the first time.

Now createSlice is a function built into Redux Toolkit, which takes an object as a parameter with 3 required fields.

The first field is name. This is important as it is used to help name the generated action types from createSlice.

The second field is the initialState, and as the name may imply, this will be what our state is initially when we first start our app.

The third field is our reducers which is where our different state handling is going to occur. In the above code, you can see that I have 3 reducers (for adding, removing, and setting todos completed state). You will also notice that the way I am managing state makes it look like it’s mutable (this is not the case, though). Behind the scenes, Redux Toolkit is leveraging a library called Immer. In short, Immer is just a library that makes handling immutable state easier to write (less boilerplate). Below is a link to the page in Redux Toolkit’s documentation that discusses it if you’re interested.

That’s really it. The above code is going to control the state of our entire app. For those of you who write all of your redux code by hand (actions and reducers), you are going to notice how much less boiler-plate this is.

The next step is to set up our store for Redux. Let’s start by creating a new file in our redux folder called store.ts.

An explanation of the above code:

There’s not much to talk about here because it is so simple, but Redux Toolkit provides an abstraction on the Redux store called configureStore. Basically, all we need to do for this to work is pass all of our slices to the reducer option in the configureStore function. Additionally, we are providing types for a few things to make TypeScript happy later. These types are going to be passed to useSelector and useDispatch (react-redux hooks) as a way to describe the types. Below is a link to the API documentation for configureStore for those who would like to know more.

Adding Redux to our React App

For those of you who have used Redux before, this process remains unchanged. This is where the package we installed earlier comes into play (react-redux). All we are going to is wrap our entire React app inside of a component provided by react-redux. To do this, we are going to edit our index.tsx file.

An explanation of the above code:

There is not a ton to explain here either, but essentially, we wrap our Provider component around the App component. This will allow us to tap into our Redux store from anywhere within our React app, as you are about to see. Below is a link to react-redux documentation on the Provider component if you are interested in learning more about it.

Integrating Redux Into Our UI

This will be the final step, and you will see just how simple Redux Toolkit will make it for us to work with react-redux.

Here is a brief explanation of what we are going to be doing before we dive in. First things first, we will not be writing our own styles for this app (you can if you would like, though). This is where Material-UI will come into play. What we are going to have is a text field and a button that is going to be responsible for adding items to our to-do list. Underneath this text field, and button is going to be our list of items. Each item will be displayed with the todo items description, a checkbox to mark the item as complete, and a delete button for removing to-dos from the list. That’s really all there is to it, so let’s write the code.

An explanation of the above code:

The first thing that we need to do is add a few lines of code to our index.tsx file. We are going to be importing and adding the CSSBaseline component from Material-UI. All this is doing is adding some intelligent resets and defaults to our CSS.

Now it’s time to write our UI. All the code in my example will live in the App.tsx file, but I highly recommend breaking things down into separate files and components if you were making an actual app.

To save confusion, I will not be diving into the details of Material-UI (for those who haven’t used it before, you don’t have to dive too deep into what each component is doing). What’s important in the above code is how we are dispatching our actions. You’ll notice how the actions are named based on how we named our reducers (addTodo, removeTodo, setTodoStatus).

Let’s talk about the useDispatch hook first and how it connects to the different items, we created in our todoSlice.ts file.

On line 46, we are dispatching the addTodo action. It’s really quite simple because we just need to pass description to it and because of how we set it up in our slice, the ID and Completed state will be generated automatically.

On line 65, we are dispatching the removeTodo action. We only need to pass the id of that todo item to it in this scenario. Inside of our resolver for removing the todo, we have code that will splice the todo item from the array based on that item's index in the array.

On line 75, we are dispatching the setTodoStatus action. In this scenario, we have to pass an object we defined in the resolvers in the todoSlice.ts file. The object contains both the id and the completed status, which we want to set the todo item to. We need these two items because we must be both able to find the to-do item in the array and also set the completed status based on its value in this object.

This explains how we are using dispatch in this scenario, but now we need to understand how the useSelector hook is working on line 25. This is important because we are using this hook to generate our list.

On line 25, you will see that we are passing an arrow function as the parameter to the useSelector hook. Basically, what this arrow function accomplishes is it will describe what the data will look like that we are getting back. In this case, we want the entire state back, so I’m simply returning the state on the other side of the arrow function. One other thing to note that is important for TypeScript is in the arrow function; the state parameter has a type of RootState which we defined earlier. Essentially, this is a dynamically generated type based entirely on the items that we pass to the store. To summarize, our todoList variable will have a type of Todo[] which we can map over to generate our list. You will see the code for this on line 53.

And that is pretty much it. We have a fully functioning app that has a responsive state using Redux. Below is my code on Github if you would like to clone my repository and use it for reference.

References and Documentation

Below are some useful references and documentation about our app.

Conclusion

Redux is a compelling and popular library that many React developers use. Even if you don’t plan on using it in your projects, it can be beneficial to know and understand it. Redux Toolkit, in my honest opinion, is the future of where a lot of Redux applications will go. It significantly cuts down on boilerplate and is currently the recommended approach by Redux. Hopefully, you gained some value from this tutorial about just how handy Redux Toolkit can be.

More content at plainenglish.io

--

--