State Management on React [Part 2] - Redux and Redux Toolkit
Tags: react, javascript, typescript, frontend
Published: 2023-05-31 19:23:25

Hi people! How are you doing? Are you ok?

I hope you guys liked the previous article where I talk about state management using the Context API. Now we will create the same application, but using **Redux**, more specifically using **React Toolkit** (this library, will make the implementation simpler and faster). 
We are going to create a simple application but we will be able to see the code of the technologies and compare the implementation. 

I'll cover these technologies in each article:

- [**Context API (part 1)**](https://dev.to/kevin-uehara/state-management-on-react-part-1-context-api-4jig)
- [**Redux (part 2)**](https://dev.to/kevin-uehara/state-management-on-react-part-2-redux-n5f)
- [**Jotai (part 3)**](https://dev.to/kevin-uehara/state-management-on-react-part-3-jotai-i7f)
- [**Recoil (part 4)**](https://dev.to/kevin-uehara/state-management-on-react-part-4-recoil-55mp)
- [**Zustand (part 5)**](https://dev.to/kevin-uehara/state-management-on-react-part-5-zustand-1jl3)

**Summary:**
- [**Introduction**](#introduction)
- [**Show me the code**](#show-me-the-code)
- [**Results**](#results)
- [**Conclusion**](#conclusion)

# Introduction

Probably Redux it is the oldest library for state management on React. I remember to use in the early days of React, when we could only control the state on class components and passing the state via prop drilling.
When the state became more complex and we need to share between components we used Redux.
But it was a new and verbose tool, where we can share the state between components. Sometimes the application managament state became complex to maintain in some cases.

**Buuuuut**, like any tool over time it evolves and develops, becoming easier.

But before I start the development of our application, let's rember how Redux works...
Redux is a library created and inspired on the **Flux** architeture created by facebook.

You can use the [Redux Dev Tools](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd) chrome extension to see the actions and state.

We need to know that Redux is formed by three main steps or flows:

- Actions
- Reducers
- Store

![Redux flow image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0t9mzriq9c1hpx13u2ys.png)

The main flow using Redux happens like the example above.

- First the View will **dispatch** an **Action**. The action is some interaction of the user with the page. For example, click on button to change the theme color of the page. We will dispatch an event called `CHANGE_THEME`.

- Now the reducer, will receive this action, will interpret and make something with this action. The reducer always will get the old state and the action. We can add some business logic on our reducer and we will replace the old state, with the new state on store. (Immutability)

- Store is where the states of our application are "stored". After the reducer change the old state to the new state on Store, all the components that are listening (subscribed) this state, it will update.

This is a summary of how redux works.
Today the most of web applications that use redux, use structure of directorys to map the Actions and create a Reducer for each feature which will need a state. Using two dependencies `redux and react-redux`. So we need to create some files to manage our actions, reducers and stores.

And nowadays, a library emerged to facilitate the implementation of redux, called `redux-toolkit`. We will be using the library to manage our state in the app. Basically, this library change the way we create the actions and reducers in a sigle file. we usually call slice, but you can call the way of you want.

Just to remember again, if you did not saw the first part, I created all components that we will use in this and next parts on the first part. Soooo if you did not saw yet, I recommend to see on: [State Management on React [Part 1] - Context API](https://dev.to/kevin-uehara/state-management-on-react-part-1-context-api-4jig).

We will use the first version of the components that we created without the Context API integration.

Now with all concepts at hands, LET'S TO THE CODE! 

# Show me the code

Let's add the dependencies that we will use:

```sh
yarn add redux react-redux @reduxjs/toolkit
```

I will create a directory on `/src` called `redux` and for each feature I will create a folder with the name of the feature. So, we have two features in our app: change theme color (dark mode) and a todo list:

![directory folders image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pdbr59gz3cqgd24rm3hb.png)

I will start with the dark mode feature. We will create a file on `theme/slice.ts` and create this code:

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

export interface ThemeState {
  isDark: boolean;
}

const initialState: ThemeState = {
  isDark: false,
};

export const slice = createSlice({
  name: "theme",
  initialState,
  reducers: {
    changeTheme: (state) => {
      return { ...state, isDark: !state.isDark };
    },
  },
});

export const { changeTheme } = slice.actions;

export const getTheme = (state: { theme: ThemeState }) => state.theme.isDark;

export default slice.reducer;
```

This single file it is creating the actions and reducers, using the `createSlice` function. So in this function we need to provide the name `theme`, provide an initial state and on reducers we will provide the object containing the functions that will update our store.

Finnaly I export the actions of `slice.actions` and export default the reducers using `slice.reducers`.

To get the theme easily I created the function to get the state called 'getTheme'.

Now for the Todos feature, let's create on `redux/todo` two files. First the types `types.ts` (my preference) and the `slice.ts`.

The `types.ts` contains just the type of our todo:

```ts
export interface ITodo {
  id: number;
  label: string;
  done: boolean;
}
```

And on the `todo/slice.ts` let's add this code:

```ts
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import { ITodo } from "./types";

const initialState: ITodo[] = [];

export const todoSlice = createSlice({
  name: "todo",
  initialState: {
    todos: initialState,
  },
  reducers: {
    addTodo: (state, action: PayloadAction<string>) => {
      const newTodo: ITodo = {
        id: Math.random() * 1000,
        done: false,
        label: action.payload,
      };

      return { ...state, todos: [...state.todos, newTodo] };
    },
    removeTodo: (state, action: PayloadAction<number>) => {
      const removed = state.todos.filter((todo) => todo.id !== action.payload);
      return { ...state, todos: removed };
    },
  },
});

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

export const getTodos = (state: { todo: { todos: ITodo[] } }) =>
  state.todo.todos;

export default todoSlice.reducer;
```

The same exactly idea we applied here. Now we have two functions to add and remove todo item. Remember the concept of immutability, so we always get the old state the increment using spread operator to update the state.

Now we need to provide the slices as a store. So we have two slicers and we need to connect to provide as state store for o our application.

We will create a single file on `redux/store.ts` to combine all slicers and configure the store. So on the `store.ts`:

```ts
import { configureStore } from "@reduxjs/toolkit";
import themeReducer from "./theme/slice";
import todoReducer from "./todo/slice";

export default configureStore({
  reducer: {
    theme: themeReducer,
    todo: todoReducer,
  },
});
```

We will combine the reducers. If you want to create another slicer, just add on this object to get mapped.

And we are done! All states are created and now let's change the components to use this states and dispatch the actions.

Let's change the `ButtonChangeTheme` adding this simple code:

### components/ButtonChangeTheme/index.tsx
```jsx
import { useDispatch } from "react-redux";
import button from "./button.module.css";
import { changeTheme } from "../../redux/theme/slice";

interface ButtonChangeThemeProps {
  label: string;
}

export const ButtonChangeTheme = ({ label }: ButtonChangeThemeProps) => {
  const dispatch = useDispatch();
  return (
    <button className={button.btn} onClick={() => dispatch(changeTheme())}>
      {label}
    </button>
  );
};
```

The `useDispatch` is from `react-redux`, so we call the action to dispatch the event. And the `changeTheme` it is working as a action for the redux. AMAZING, isn’t it?

Now on our `Content` dummy component, let's consume the state using the `useSelector` of `react-redux`:

### components/Content/index.tsx
```jsx
import { useSelector } from "react-redux";
import { getTheme } from "../../redux/theme/slice";

interface ContentProps {
  text: string;
}

export const Content = ({ text }: ContentProps) => {
  const isDark = useSelector(getTheme);

  return (
    <div
      style={{
        height: "30vh",
        width: "100vw",
        color: isDark ? "#fff" : "#111827",
        backgroundColor: isDark ? "#111827" : "#fff",
      }}
    >
      {text}
    </div>
  );
};
```

Now on our `FormTodo` component, let's dispatch the action to add a todo item:

### components/FormTodo/index.tsx

```jsx
import style from "./Form.module.css";
import { Button } from "../Button";
import { Input } from "../Input";
import { useState } from "react";
import { useDispatch } from "react-redux";
import { addTodo } from "../../redux/todo/slice";

export const FormTodo = () => {
  const [todo, setTodo] = useState("");
  const dispatch = useDispatch();

  const handleAddTodo = () => {
    dispatch(addTodo(todo));
    setTodo("");
  };

  return (
    <div className={style.formContainer}>
      <Input
        value={todo}
        label="Todo"
        onChange={(evt) => setTodo(evt.target.value)}
      />
      <Button label="Add" onClick={handleAddTodo} />
    </div>
  );
};
```

And finnaly, let's change the `ListTodo` component to dispatch the action to remove the todo item and consume the list of todos using the selector:

### components/ListTodo/index.tsx

```jsx
import { useDispatch, useSelector } from "react-redux";
import style from "./ListTodo.module.css";
import { getTodos, removeTodo } from "../../redux/todo/slice";

export const ListTodo = () => {
  const dispatch = useDispatch();
  const todos = useSelector(getTodos);

  const handleRemoveTodo = (id: number) => {
    dispatch(removeTodo(id));
  };

  return (
    <ul>
      {todos.map((todo) => (
        <li className={style.item} key={todo.id}>
          <label>{todo.label}</label>
          <i
            className={style.removeIcon}
            onClick={() => handleRemoveTodo(todo.id)}
          />
        </li>
      ))}
    </ul>
  );
};
```

### EASY PEASY

To finish, lets add the `Provider` in our app tree on `main.tsx`, passing the store:

```jsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "./index.css";

import { Provider } from "react-redux";
import store from "./redux/store.ts";
import { ButtonChangeTheme } from "./components/ButtonChangeTheme/index.tsx";
import { Content } from "./components/Content/index.tsx";

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  <React.StrictMode>
    <Provider store={store}>
      <ButtonChangeTheme label="Change Theme" />
      <Content text="Hello World!" />
      <App />
    </Provider>
  </React.StrictMode>
);
```

And now we finished the application using redux as global state management!

# Results

If you remember, on first part of this article of Context API. Some problems of it was the re-render because of when we update the state, all the childrens will be rendered again. 

But with redux, using the selector, we can manage the state and update just only the components that use that state. 

Let's see on React Dev Tools:

First using highlight of render of component:

![Highlight of component rendering gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yxhsbiovxpwcxl3paytn.gif)

**We can see that when we change the theme, the form is not affected by re-render by highlight.**

Now using the profiler viewer record:

![Profile viewer record of components rendering gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6v9ail1kjx8etdrxnw9b.gif)

And additionally you can use the Redux Dev Tools to see the actions dispatched and the state:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/efrt3dvxrazbmxhpnscv.gif)

We see that the both the change theme and remove todo just affeect only the components that use THAT state. And this is amazing, because we are talking about of fixing a problem of a simple way, without having to create out-of-the-box solutions like useMemo or Memo.

# Conclusion

I'm not saying that redux is the best library and that you should use it in your project. So much so that the purpose of these articles is to compare the application and implementation of each state manager.

But it's a tool that I am presenting to you in a superficial way. If you are interested, look for the documentation to go deeper into the concept of the tool.

So in summary, in this article we saw how we can implement the redux, using the new library `react-toolkit` to manage our states, creating slicers and combine on our store.

In the next part, I will talk about (spoilers) another state manager (for now what I've been most enjoying using), called **JOTAI**. But for now, that's it!

Some references:

- [React Redux](https://react-redux.js.org/)
- [React Redux Toolkit](https://redux-toolkit.js.org/)
- [My repository](https://github.com/kevinuehara/react-state-management)
- [Linkedin](https://www.linkedin.com/in/kevin-uehara/)

That's all folks!

I hope you enjoyed it and added some knowledge. See you in the next parts!