DEV Community

ISIAKA ABDULAHI AKINKUNMI
ISIAKA ABDULAHI AKINKUNMI

Posted on

Getting Started With Redux-ToolKit (RTK)

Managing state is an important aspect of React, For a smaller project, using useState or useReducer is a good way to manage state. But as the application grows complex, we need an efficient way to handle it, React-Redux provides us with global state management and in this article we will explore the concept of state management using Redux-ToolKit (RTK).

Table of Content

Introduction

When an action is performed,a state change is expected to happen and trigger the rendering of UI. Managing state can be done using a useState or useReducer, It could be complex especially if those components are located in different parts of the application. Sometimes this can be solved by "lifting state up" to parent components, but that doesn't always help.

One way to solve this is to extract the shared state from the components, and put it into a centralized location outside the component tree where any component can access the stateor trigger actions, no matter where they are in the tree. This is the first of three articles. Other articles are

In those articles, I will explain how to use RTK queries to make API calls in efficient ways rather than installing other packages, I will also explain redux-persist as an alternative to saving to persist our state or save with details in our App. see you soon.

What is React-redux

React-Redux is a popular JavaScript library that helps developers manage the state of their applications. React-Redux provides a way for a React application to communicate with a central store that holds the state of the application. If you are familiar with react-redux, there are several challenges using it as explained by the documentation ranging from

1. Configuring a Redux store is too complicated
2. Installing many Packages
3. Too much boilerplate code
Enter fullscreen mode Exit fullscreen mode

With those challenges, RTK is meant to solve them and provide a way to write efficient ways to set up and store and define reducers,

Installation

For an existing project, run the following code in your terminal

npm install @reduxjs/toolkit react-redux

OR

yarn add @reduxjs/toolkit

Enter fullscreen mode Exit fullscreen mode

For a new project and this tutorial, we will create an App with redux template, run the code below, our App name is redux-tutorial

npx create-react-app redux-tutorial --template redux

Enter fullscreen mode Exit fullscreen mode

After the installation, run


cd redux-tutorial

code .

npm start

Enter fullscreen mode Exit fullscreen mode

Your package.json file should like this, redux-toolkit and react-redux will be installed.

redux-tool-kit

Setting up

In this Tutorial, we will be building a simple Todo list to illustrate our work. We need to basically go through three basic step as listed below

*Only necessary if you are using an existing App

In our features folder, a subfolder of src, create another folder called todo where all our configurations will be. For those that installed with redux template, all configurations have been done. For existing project, create a folder store and add index.js.

ConfigureStore

The configureStore function is used to create a Redux store that holds the complete state tree of our App. Configure store accepts reducers as the required parameters, others parameters that can be included are

  • Thunk middleware
  • Redux DevTools
  • PreloadedState​
  • Enhancers​

Lets create our storeby importing the following

src/app/store.js OR ./store


import { configureStore } from '@reduxjs/toolkit';
import todoReducer from  "features/todo/todoSlice.js"
export const store = configureStore({
  reducer: {
    todos: todoReducer,
  },
});

Enter fullscreen mode Exit fullscreen mode

Here, we import our todoReducer (which will be created soon). the import was done using absolute path. Read more about absolute path in my article here. We can have multiple reducers combined together. later on, we will use todos as the key to access our state.

Wrap our App with Provider from react-redux


import React from "react";
import { createRoot } from "react-dom/client";
import { Provider } from "react-redux";
import { store } from "./app/store";
import App from "./App";

const container = document.getElementById("root");
const root = createRoot(container);

root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

Enter fullscreen mode Exit fullscreen mode

CreateSlice

This helps us to write reducers without the need to spread our state. Redux Toolkit allows us to write "mutating" logic in reducers. It doesn't actually mutate the state because it uses the Immer library, It also automatically generates action creator functions for each reducer. It literarily saves us with writing our actions type logic repetitively.

In features folder, create another folder todo and add todoSlice.js where we write our todoSlice

todoSlice.js


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

const initialState = {
  todoList: [],
};

export const todoSlice = createSlice({
  name: "todos",
  initialState,

  reducers: {},
});
const { actions, reducer } = todoSlice;

export const {} = actions;

export default reducer;

Enter fullscreen mode Exit fullscreen mode

This is a boilerplate for writing our slices, in our createSlice function, we passed in our name, the initial State and our reducers.

Actions

let's write our first action, addTodo add a new todo to the list and we create it in reducers object as below

Add Todo

addTodo: (state, action) => {

state.todoList.push(action.payload);

}

Enter fullscreen mode Exit fullscreen mode

Here we are using the push method to add new todo to our list. action.payload is the todo that will be added to todoList.

Delete Todo

To be able to delete from the list, we use the index to select a particular todo and use the array method of splice. here is the code:

 deleteTodo: (state, action) => {
      state.todos.splice(state.todos.indexOf(action.payload), 1);

},

Enter fullscreen mode Exit fullscreen mode
Update Todo

 updateTodo: (state, action) => {
      const todo = state.todoList.findIndex(action.payload.id);
      state.todos[todo] = action.payload;
 }

Enter fullscreen mode Exit fullscreen mode

We can export all our actions and our final code like this


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

const initialState = {
  todoList: [],
};

export const todoSlice = createSlice({
  name: "todos",
  initialState,

  reducers: {
    addTodo: (state, action) => {
      state.todoList.push(action.payload);
    },
    deleteTodo: (state, action) => {

   state.todoList.splice(state.todoList.indexOf(action.payload), 1);
    },
    updateTodo: (state, action) => {
      const todo = state.todoList.findIndex(action.payload.id);
      state.todoList[todo] = action.payload;
    },
  },
});

const { actions, reducer } = todoSlice;

export const { addTodo } = actions;

export default reducer;

Enter fullscreen mode Exit fullscreen mode

With this we concluded writing on redux logic, last thing we need to do is to import it in our App.

useDispatch and useSelector

The two hooks work to get set and get data from our store. if we need to modify the state, useDispatch will be used to dispatch an action while if we need to access our state, useSelector will be used.

Todo App

For this, we created our Todo component in the root of our src folder, our folder structure should look like this

folder_structure

We create a simple UI and you can have access to the code in the linked repository.. Here is the code in our Todo.js file


import { useState } from "react";
import {  useSelector } from "react-redux";

const Todo = () => {
  const [todo, setTodo] = useState("");
  const state = useSelector((state) => state.todos.todoList);

  return (
      <div className="todo">
      <h3>Simple Todo App</h3>
   <div className="input__container">

      <input
        type="text"
        value={todo}
        onChange={(e) => setTodo(e.target.value)}
      />

      <button>Add Todo</button>
    </div>
     <ol>
        {state.length > 0 &&
          state.map((todo, index) => {
            return (
              <li key={index}>
                <h6>{todo} </h6>

                <button name="edit">Edit</button>

                <button name="delete">
                  Delete
                </button>
              </li>
            );
          })}
      </ol>
    </div>
  );
};

export default Todo;


Enter fullscreen mode Exit fullscreen mode

The first thing we do here is to get the current state of our todoList using useSelector hook, we have

Get Initial State

const state = useSelector((state) => state.todos.todoList);

Enter fullscreen mode Exit fullscreen mode

todos here refer to the name of the reducer we used when configuring our store. So we have access to our todoList array which contains our initialState and if we log it to console, we have

console.image

Add a Todo

To add to the list, we need to dispatch our addTodo action as shown below. we will use useDispatch hook.

  • first we call the useDispatch and assigned it to dispatch variable.
  const dispatch = useDispatch();
Enter fullscreen mode Exit fullscreen mode
  • We dispatch our action when we clicked the button, with our todo as a paramater as shown below. we checked if there's todo before we dispatch our action and clear our input field afterwards

     <button onClick={() => {
                 if (!input) return;
                 dispatch(addTodo(input));
                 setInput("");
                 }}
     >
     Add Todo
     </button>

Enter fullscreen mode Exit fullscreen mode

on the click of Add Todo button, we have something similar to this

Added todolist

Delete a todo

Similar to what we did for addTodo, we will pass the index a todo and dispatch our deleteTodo action


import { addTodo, deleteTodo } from "features/todo/todoSlice";

Enter fullscreen mode Exit fullscreen mode

In our edit button, we add the code to set our todo to the input value, here is how our button code looks like

 <button name="delete" onClick={()=>dispatch(deleteTodo(index))}>
 Delete
 </button>

Enter fullscreen mode Exit fullscreen mode
Update a todo

Here , we need to select a particular todo item and make update to it, full details to the implementation is available in the repo.

Thank you for reading. Please leave a comment if you have any question or clarification and I hope you've learned something new from this post. Want to stay up to date with regular content regarding JavaScript, React and React-Native? Follow me ❤️ on LinkedIn.

Top comments (0)