Creating a To-do list app using Redux Toolkit
Published: 2022-02-23 19:08:54

# Introduction

Redux Toolkit is a react package for state management built on redux. In this tutorial, I’ll explain how to use the Redux toolkit by building a small to do list app that keeps its state using Redux Toolkit. I personally prefer redux toolkit over regular redux because it is much easier to use. The creators of the package intended to make it the default way to write Redux logic. They eliminated a bunch of boilerplate code and made redux state management easier to create. 

# The UI

I won’t be focusing on the UI in this tutorial, so I made this github repository that you can clone that has the UI already created for you. ([link](https://github.com/yosraemad/redux-toolkit-tutorial-UI))

Now we have the UI that looks like this:

![initial UI](https://cdn.hashnode.com/res/hashnode/image/upload/v1645639231213/7u_Yi6ejH.png)

# Using Redux Toolkit

Now that we have our UI ready, you’ll see that I’ve hard-coded the to-do list items. Our goal in this part of the article is to make the user able to add and remove to-dos from the list.

## Installing Redux Toolkit

After cloning the repository above and installing packages, you should install redux toolkit and react-redux using the following command:

```bash
npm install @reduxjs/toolkit react-redux
```

## Creating the Todo Slice

The slice is the component that keeps track of the app’s state. In it, You should define the initial state and the functions that will be needed to change the state when necessary. 

1. To build the slice, you need to import `createSlice` . Which is a function inside the Redux Toolkit package.
    
    ```jsx
    import { createSlice } from "@reduxjs/toolkit";
    ```
    
2. Next, define your initial state. In this case, two variables will be part of the state:
    - `count` : an integer that keeps track of the number of to-dos in the app (initially equals 0)
    - `todos`: a list that contains all the todos that the user added (initially empty)
    
    ```jsx
    const initialState = {
      count: 0,
      todos: [],
    };
    ```
    
3. Now, use the `createSlice` function that was imported. It takes three arguments:
    - Name of the slice (in this case `todo`)
    - Initial state (defined above)
    - reducers (the functions that will be used to change the state values)
    
    ```jsx
    export const todoSlice = createSlice({
      name: "todo",
      initialState,
      reducers: {
        addTodo: (state, action) => {
          const todo = {
            id: Math.random() * 100,
            text: action.payload,
          };
          state.todos.push(todo);
          state.count += 1;
        },
        removeTodo: (state, action) => {
          state.todos = state.todos.filter((todo) => todo.id !== action.payload);
          state.count -= 1;
        },
      },
    });
    ```
    
    Here, two functions were added, one is `addTodo` and the other is `removeTodo`:
    
    - `addTodo` → creates a new todo item using the text passed in the argument and assigns a random id to it. It pushes the created todo to the todos list and increases the count value.
    - `removeTodo` → removes the todo item using the id given in the arguments from the todos list and decrements the count value.
    
    Note that to get the argument passed to the function, we use `action.payload`. If you need more than one argument, you can send the arguments as one object and access it using the payload. For example:
    
    ```jsx
    action.payload.variable
    ```
    
4. Export the functions to be able to use them in the app. You can do so by accessing `todoSlice.actions`.
    
    ```jsx
    export const { addTodo, removeTodo } = todoSlice.actions;
    ```
    
5. Finally, export the reducer. This will be used in the store to be able to provide the state to the app (see next section)
    
    ```jsx
    export default todoSlice.reducer;
    ```
    

### Full `TodoSlice` code

```jsx
import { createSlice } from "@reduxjs/toolkit";

const initialState = {
  count: 0,
  todos: [],
};

export const todoSlice = createSlice({
  name: "todo",
  initialState,
  reducers: {
    addTodo: (state, action) => {
      const todo = {
        id: Math.random() * 100,
        text: action.payload,
      };
      state.todos.push(todo);
      state.count += 1;
    },
    removeTodo: (state, action) => {
      state.todos = state.todos.filter((todo) => todo.id !== action.payload);
      state.count -= 1;
    },
  },
});

export const { addTodo, removeTodo } = todoSlice.actions;

export default todoSlice.reducer;
```

## Creating the store

The store is the component that you provide to the redux provider that makes it aware of the existence of the state.

1. Create a folder in your src folder called “store” and create an index.js file inside
    
    ![create a store folder](https://cdn.hashnode.com/res/hashnode/image/upload/v1645639274244/4-ZI9ku8-.png)
    
2. Add the following code to the file. This will make the store listen to our reducer and that’s how we’ll be able to access the variables and the functions inside our slice. We’ll name our reducer “todo”
    
    ```jsx
    import { configureStore } from "@reduxjs/toolkit";
    import todoReducer from "../features/todoSlice";
    
    const store = configureStore({
      reducer: {
        todo: todoReducer,
      },
    });
    
    export default store;
    ```
    

## Adding the store to our app.

To provide the store to the app, use the normal redux provider.

In your index.js file add the following code:

```jsx
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import "./index.css";
import store from "./store";
import { Provider } from "react-redux";

ReactDOM.render(
  <Provider store={store}>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </Provider>,
  document.getElementById("root")
);
```

# Using the State

To use the state that was just created in the app, import `useSelector` and `useDispatch` from redux. Also, import `addTodo` and `removeTodo` from the slice file.

1. Add the following imports to your App.js file:
    
    ```jsx
    import { useSelector, useDispatch } from "react-redux";
    import { addTodo, removeTodo } from "./features/todoSlice";
    ```
    
2. In the App function, get both the count and todo states using `useSelector`. Note that to access any of those states, you should access the reducer name that was specified in the store file like this:
    
    ```jsx
    const count = useSelector((state) => state.todo.count);
    const todos = useSelector((state) => state.todo.todos);
    ```
    
3. Extract the `dispatch` function that will be used to run `addTodo` and `removeTodo` functions.
    
    ```jsx
    const dispatch = useDispatch();
    ```
    
4. Write `handleAddTodo` function that will be triggered when the form is submitted.
    
    ```jsx
    const handleAddTodo = (e) => {
        e.preventDefault();
        dispatch(addTodo(input));
    };
    ```
    
    > Calling `e.preventDefault()` is necessary because the form’s default action is to refresh the page after submitting. If you let it refresh the page, all our state will be reset.
    > 
5. For the `handleTodoDone` function, it will be triggered it when the user clicks on a todo item. The id of the todo will be used to identify which todo is removed.
    
    ```jsx
    const handleTodoDone = (id) => {
        dispatch(removeTodo(id));
    };
    ```
    
6. In the form element, add an `onSubmit` action that points to `handleAddTodo` 
    
    ```jsx
    <form className="App-form" onSubmit={handleAddTodo}>
    ```
    
7. To show the list of to-dos, map the `todos` list to the `TodoItem` component and pass the id to the key and id attributes. In addition, pass the text of the todo and the `handleTodoDone` function.
    
    If the count is equal to 0, “No todos” will be displayed to the user.
    
    ```jsx
    <div className="Todos">
            {count > 0 &&
              todos.map((todo) => (
                <TodoItem
                  key={todo.id}
                  text={todo.text}
                  id={todo.id}
                  onCheck={handleTodoDone}
                />
              ))}
            {count === 0 && <p>No todos</p>}
    </div>
    ```
    
8. In the TodoItem file, add a function that listens to clicking on the item <div>.
    
    Full TodoItem.js file:
    
    ```jsx
    import "./TodoItem.css";
    
    const TodoItem = (props) => {
      const deleteTodo = () => {
        props.onCheck(props.id);
      };
      return (
        <div className="todo" onClick={deleteTodo}>
          <input type="checkbox"></input>
          <label>{props.text}</label>
        </div>
      );
    };
    
    export default TodoItem;
    ```
    
9. Your app.js file should look like this now:
    
    ```jsx
    import { useState } from "react";
    
    import "./App.css";
    
    import TodoItem from "./components/TodoItem";
    import { useSelector, useDispatch } from "react-redux";
    import { addTodo, removeTodo } from "./features/todoSlice";
    
    function App() {
      const [input, setInput] = useState("");
    
      const count = useSelector((state) => state.todo.count);
      const todos = useSelector((state) => state.todo.todos);
      const dispatch = useDispatch();
    
      const handleAddTodo = (e) => {
        e.preventDefault();
        dispatch(addTodo(input));
      };
    
      const handleTodoDone = (id) => {
        dispatch(removeTodo(id));
      };
      return (
        <div className="App">
          <h1>TODO List</h1>
          <form className="App-form" onSubmit={handleAddTodo}>
            <input type="text" onInput={(e) => setInput(e.target.value)} />
            <button type="submit">+</button>
          </form>
          <div className="Todos">
            {count > 0 &&
              todos.map((todo) => (
                <TodoItem
                  key={todo.id}
                  text={todo.text}
                  id={todo.id}
                  onCheck={handleTodoDone}
                />
              ))}
            {count === 0 && <p>No todos</p>}
          </div>
        </div>
      );
    }
    
    export default App;
    ```
    
# Final Output

![output.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1645639745587/TWqh8nQFW.gif)

# Conclusion

That’s it for the redux toolkit tutorial, you can find the full code [here](https://github.com/yosraemad/redux-toolkit-tutorial). I personally prefer redux toolkit over regular redux because it lessens the boiler plate code a lot. No one likes to write the same code over and over again right? I hope you enjoyed this tutorial, your feedback is more than welcome! In the next tutorial, I’ll be connecting this to-do list app to firebase so stay tuned!