State management with Redux in React
Tags: javascript, react, redux, webdev
Published: 2023-03-04 08:29:56

## Introduction

State management is very necessary as it helps to make data accessible in any part of your application without repeatedly querying the server for the same data, with state management you query for the data ones and store it in a particular section in the app and then fetched the data from the store.

And for this article, you will be using redux (redux-toolkit) as a state management tool.

## Understanding Redux

Redux (Redux toolkit) is one of the popular state management tools used in modern Javascript UI frameworks like React, Vue, and Angular, amongst all other state management tools is easier to store data and also retrieving too which you are going to see in a minute, for more understanding you can visit the [Redux](https://redux-toolkit.js.org/introduction/getting-started) website for a forward explanation of what Redux is used for and any other detailed information on redux (redux toolkit), also for this particular project we will be using react.js to understand how to use redux (redux toolkit).

## What is React.js

React.js is a javascript UI framework that was built by Facebook and is been managed by Facebook developers, it was developed to help split some parts of your web UI into smaller components thereby making those components reusable and a lot of other awesome features too I recommend checking their [official website](https://reactjs.org) for more awesome functionalities of reactjs and how to use them.

## Why Redux

One great thing about redux (redux toolkit) is that it let you split your store data into different files and also combine them using the combineReducers() method, And also it makes passing data from one component to the other easier and seamless, instead of passing from one parent component to children and child to sub child which can get confusing when working in bigger projects, now you store 

( Dispatch ) the data in the store and retrieve them from the store into any component you would want to use it.

## **Prerequisites**

The important tool to have for this process is node.js before now you are expected to have [Node >= 14.0.0 and npm >= 5.6](https://nodejs.org/en/)  installed on your machine, if you don’t have You’ll need to download them now [click here](http://nodejs.org) to download.

And also basic understanding of ES6

Now That has been done let’s continue if you already have a reactjs project you can skip to **Installing Redux in a React project** if you do not have a reactjs project set up already let's go to the next.

## Setting up a new react.js project

In setting up a reactjs project we will be using the create-react-app, and for this, you have to open your command line (command prompt) and type.

```jsx
npx create-react-app my-app-name
```

 

with this, you have successfully created a new react app, up to the next

## Installing Redux in a React project

If  you just installed a new react app with us, still on your terminal you can navigate to the new project by typing 

```jsx
cd my-app-name 
```

and if already have a project already you can open the project on the terminal,

Now we are all on our projects on the terminal it is time to install redux on our react project, to do this we will type

npm install react-redux

with this done we now have redux installed in our app 

```jsx
npm install react-redux
```

now we are done creating and installing it to run our app, and to do that on the terminal type

```jsx
npm start
```

## Setting up the Redux store

For the purpose of learning we will be building a simple to-do app that will help us understand the basic concept of using the Redux store.

 We will be setting up our store for the TODO app 

Doing this in your src folder is the best practice to create a folder called the store, here is where all your data will be stored just to have a nice and neat workflow. And in your Store folder create a file it can be called anything of your choice but for this, we will be calling it index.js.

Now in your index.js file firstly you have to import the createStore method from the redux library

and also export the createStore store you can just copy the below and paste it into your index.js file    

```jsx
import {createStore} from 'redux'

export const store = createStore()
```

Now the createStore method accepts two parameters, first is the [reducer](https://redux-toolkit.js.org/rtk-query/api/created-api/redux-integration#reducer) your want to use and the second is the initial state of the [reducer](https://redux-toolkit.js.org/rtk-query/api/created-api/redux-integration#reducer) which is not often nessceary because it can also be passed with the [reducer](https://redux-toolkit.js.org/rtk-query/api/created-api/redux-integration#reducer), and this is the method we will be using to set up a reducer for our To-Do app, therefore we have to update our index.js file we created in the store 

you can just copy the code below

```jsx
import {createStore} from 'redux'
const INITIAL_STATE = {
    todos : []
};
const reducer = (state = INITIAL_STATE, action) => {
    switch (action.type) {
        case "ADD_TODO":
            return {
                ...state,
                todos : [...state.todos,action.payload]
            };
        case "COMPLETED_TODO":
            return {
                ...state,
								
            };
        case "REMOVE_TODO":
            return {
                ...state,
                
            };
        default:
            return state;
    }
};
export const store = createStore(reducer)
```

And if you do not understand how the reducer hook works I do recommend checking out [react.js official docs](https://beta.reactjs.org/learn/extracting-state-logic-into-a-reducer) to understand how it works.

This reducer simply adds, update and remove an item from the store.

We are not done yet one last thing in your main.jsx or index.js file located in the src folder you have to import Provider from the react-redux library and also import the index.js file we created in the store 

you can copy the code below

```jsx
import { Provider } from 'react-redux';
import { store } from './Store/index';
```

After importing, you have to wrap your exported app component with the Provider, then in the Provider, it has an attribute called the store, and you pass the imported store into it.

you can copy the code below

```jsx
<Provider store={store}>
    <App />
</Provider>
```

Now we are done setting up our store and connecting to the store lets build a simple To-Do UI , for this you dont have to worry as i will simply be pasteing all code here, but if you already have a design or any other project you can skip to **Integrating Redux into your React components** else you can copy the code below and paste it in the App.js file in the src folder 

```jsx
import {  useState } from 'react';
import './App.css';
function App() {
  const [todo,setTodo] = useState('');
  const submit = (e) => {
    e.preventDefault();
    console.log(todo);
    setTodo('')
  }
  return (
    <div className="App">
      <div className="body">
        <form onSubmit={submit} style={{ 'padding': '0px 0px 12px 0px', }}>
          <input required 
								 value={todo} 
								 onChange={(e)=> setTodo(e.target.value)} 
								 type="text" 
								 placeholder='Enter TODO task'/>
          <button type='submit'>ADD TODO</button>
        </form>
        <div>
          <div style={{ 'padding': '0px 0px 12px 0px', }}>TODO's</div>
        </div>
      </div>
    </div>
  );
}

export default App;
```

and in your app.css 

```jsx
.body{
  margin: 0px auto;
  max-width: 800px;
  padding: 10px;
}
.todoCard{
  position: relative;
  border: 1px solid gray;
  margin-top: 7px;
  padding: 4px;
  border-radius: 9px;
  margin: 0px auto;
  max-width: 800px;
}

.wrapper{
  display: flex;
  width: 100%;
}
.todoText{
  flex-grow: 1;
  font-size: small;
}
.doneBtn{
  font-size: 12px;
  padding: 5px 12px;
  border-radius: 9px;
  text-transform: uppercase;
}
.btn-color1{
  background-color: #1a7719;
  color: aliceblue;
  cursor: pointer;
}
.btn-color2{
  background-color: #b0b3b0;
  pointer-events: none;
}
```

After this, your UI should like 


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

if you have this, that means we are good to go, it's time to connect our component to access data from the store.

## Integrating Redux into your React components

Firstly on the component where you want to access the data you have to import connect from react-redux, it should look like this.

```jsx
import { connect } from 'react-redux'
```

After importing this, you have to export the connect alongside the file name which in our case is App you have to rewrite the export to look like this

```jsx
export default connect()(App)
```

At the end of this process, your component should look like the snippet below.

```jsx
import {  useEffect, useState } from 'react';
import React from 'react'
import { connect } from 'react-redux'
import './App.css';
function App() {
  const [todo,setTodo] = useState('');
  const submit = (e) => {
    e.preventDefault();
    setTodo('')
  }
  useEffect(() => {
    
  }, [])
  
  return (
    <div className="App">
      <div className="body">
        <form onSubmit={submit} style={{ 'padding': '0px 0px 12px 0px', }}>
          <input required 
								 value={todo} 
								 onChange={(e)=> setTodo(e.target.value)} 
								 type="text" 
								 placeholder='Enter TODO task'/>
          <button type='submit'>ADD TODO</button>
        </form>
        <div>
          <div style={{ 'padding': '0px 0px 12px 0px', }}>TODO's</div>
        </div>
      </div>
    </div>
  );
}
export default connect()(App)
```

if you have done this you have successfully connected your component to the store as simple as that,

now it’s time to dispatch data into the redux store.

## Dispatching data in the store

In dispatching data to the store, inside the connect method that was been exported we can pass a function called **mapDispatchToProps** this name is totally up to you, you can call it whatever you wish to its just a name we are giving to the function then pass it into the connect method.

This function, in turn, return all action that can be performed in the store which for now will be to add to the store.

**NOTE:** Your dispatch type must be the same as what is in the reducer store

and the payload contains the actual data to be stored 

i think the code snippet will explain more.

```jsx
const mapDispatchToProps = (dispatch) =>{
  return{
      addTodo: (todo) => {
        dispatch({type:"ADD_TODO" , payload : { todo ,status:false}})
      }
  }
}

export default connect(mapDispatchToProps)(App)
```

- Functional component
    
    And to access the actions in UI or in our case our submit function in the functional component, you have to first pass the props into the function, because it’s from the props you can access the dispatch actions.
    
    and in the submit function created, you can the addTodo action and then pass the todo from the input to it. with the code below you can understand more.
    
    ```jsx
    import {  useEffect, useState } from 'react';
    import React from 'react'
    import { connect } from 'react-redux'
    import './App.css';
    function App(props) {
      const [todo,setTodo] = useState('');
      const submit = (e) => {
        e.preventDefault();
        props.addTodo(todo)
        setTodo('')
      }
      useEffect(() => {
        
      }, [])
      
      return (
        <div className="App">
          <div className="body">
            <form onSubmit={submit} style={{ 'padding': '0px 0px 12px 0px', }}>
              <input required 
    								 value={todo} 
    								 onChange={(e)=> setTodo(e.target.value)} 
    								 type="text" 
    								 placeholder='Enter TODO task'/>
              <button type='submit'>ADD TODO</button>
            </form>
            <div>
              <div style={{ 'padding': '0px 0px 12px 0px', }}>TODO's</div>
            </div>
          </div>
        </div>
      );
    }
    
    const mapDispatchToProps = (dispatch) =>{
      return{
          addTodo: (todo) => {
            dispatch({type:"ADD_TODO" , payload : { todo ,status:false}})
          }
      }
    }
    
    export default connect(mapDispatchToProps)(App)
    ```
    
- Class component
    
    For to access the props you have to add this and you don’t have to pass the props through the component this should be the output below.
    
    ```jsx
    import React, { Component } from 'react'
    import { connect } from 'react-redux'
    import './App.css';
    
    export class App extends Component {
      constructor(props) {
        super(props)
        this.state = {
          todo : '',
        }
      }
      submit(e){
        e.preventDefault();
        this.props.addTodo(this.state.todo)
        this.setState({todo : ''})
      }
      render() {
        return (
          <div className="App">
            <div className="body">
              <form onSubmit={e => this.submit(e)}
    							  style={{ 'padding': '0px 0px 12px 0px', }}>
                <input required 
    									 value={this.state.todo} 
    									 onChange={(e)=> this.setState({todo : e.target.value})}
    									 type="text"
    									 placeholder='Enter TODO task'/>
                <button type='submit'>ADD TODO</button>
              </form>
              <div>
                <div style={{ 'padding': '0px 0px 12px 0px', }}>TODO's</div>
              </div>
            </div>
          </div>
        )
      }
    }
    
    const mapDispatchToProps = (dispatch) =>{
      return{
          addTodo: (todo) => {
            dispatch({type:"ADD_TODO" , payload : { todo ,status:false}})
          }
      }
    }
    
    export default connect(mapDispatchToProps)(App)
    ```
    

## Accessing data from the store

Now we have successfully dispatched data into the store we have to retrieve the data stored

The connect method can also accept another function as a parameter which in our case we can call it mapStateToProps again this name is totally up to you, what it does is that it helps you access the data in the store, this function accepts the state which holds all the data in the store which in turn we can access those data in the state and assign them to a key that we can use to access them in our UI

the code snippet below should explain more about it.

```jsx
const mapStateToProps = (state) => ({
  list : state.todos
})

const mapDispatchToProps = (dispatch) =>{
  return{
      addTodo: (todo) => {
        dispatch({type:"ADD_TODO" , payload : { todo ,status:false}})
      }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(App)
```

This is now how your code should be.

Now that we have gotten the data in our store we have to display them therefore we will be updating the UI

- Functional component
    
    If you are using the functional component to access the list data you can copy the code below.
    
    ```jsx
    return (
        <div className="App">
          <div className="body">
            <form onSubmit={submit} style={{ 'padding': '0px 0px 12px 0px', }}>
    	          <input required
    									 value={todo} 
    									 onChange={(e)=> setTodo(e.target.value)} 
    									 type="text" placeholder='Enter TODO task'/>
              <button type='submit'>ADD TODO</button>
            </form>
            <div>
              <div style={{ 'padding': '0px 0px 12px 0px', }}>TODO's</div>
              {
    					  props.list.map((todo,i) => (
    					    <div className="todoCard" 
    										 key={i} style={{'margin':'8px 0px 0px 0px'}}>
    					      <div className="wrapper">
    					        <div className="todoText">{todo.todo}</div>
    					      </div>
    					    </div>
    					  ))
    					}
            </div>
          </div>
        </div>
      );
    ```
    
- Class component
    
    And for the class component copy the code below.
    
    ```jsx
    return (
          <div className="App">
            <div className="body">
              <form onSubmit={e => this.submit(e)} 
    								style={{ 'padding': '0px 0px 12px 0px', }}>
                <input required 
    									 value={this.state.todo} 
    									 onChange={(e)=> this.setState({todo : e.target.value})} 
    									 type="text" placeholder='Enter TODO task'/>
                <button type='submit'>ADD TODO</button>
              </form>
              <div>
                <div style={{ 'padding': '0px 0px 12px 0px', }}>TODO's</div>
                {
                  this.props.list.map((todo,i) => (
                    <div className="todoCard" 
    										 key={i} 
    										 style={{'margin':'8px 0px 0px 0px'}}>
                      <div className="wrapper">
                        <div className="todoText">{todo.todo}</div>
                      </div>
                    </div>
                  ))
                }
              </div>
            </div>
          </div>
        )
    ```
    

Wow, that's great we are done with all now it should be working just fine let's test it out.

## Using multiple stores

Now all is working very fine with using just one reducer or one store, in a big react project you can have more than one store such as in our case having a store that holds the users’ data, now if we want to store the user's data in the same store as the To-Do’s we can, but this is not the best practices,

the best practice is to create your reducers in different files, then import them in the index.js file in the store folder the folder structure should be this 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/500nuouz6clc8phjqqm4.PNG)

now you can update  the index.js file by importing the reducers like so

```jsx
import {createStore} from 'redux'
import {TodoReducer}  from './Reducers/TodoReducer'
import { UserReducer } from './Reducers/UserReducer'

export const store = createStore(TodoReducer)
```

As you can see we no longer have one reducer, but then we can only pass one reducer at a time directly to the createStore method, so how do we solve this **THE BIG QUESTION**.

Don’t worry it's as simple as ABC.

Firstly you have to import the combineReducers method from the redux library and then pass it into the createStore method, then the combineReducers in turn can accept an object that contains the list of all the imported reducers.

```jsx
import {combineReducers ,createStore} from 'redux'
import {TodoReducer}  from './Reducers/TodoReducer'
import { UserReducer } from './Reducers/UserReducer'

export const store = createStore(combineReducers({TodoReducer,UserReducer}))
```

Now knowing that we no longer have one reducer, the way of accessing the data in the different stores changes a  bit, in our app.js or the component where you are accessing the store, you have to call the particular store you want to access.  

```jsx
const mapStateToProps = (state) => ({
  list : state.TodoReducer.todos
	user : state.UserReducer
})
```

just like this, we have successfully connected to the two stores 

You don’t have to worry about dispatching data into the store because it will still work just fine. 

All you have to do is you should not have the same `action.type` case in different stores, just as we have the `case “ADD_TODO”` in the TodoReducer store we should not have a `case “ADD_TODO”` in our UserReducer.

## Bonus

If you have not noticed or you are using redux before now but you keep having the issue of the data in your state going out once the page refreshes or when you route to another page the data in your store clears, well don,t worry that is where we have to persist the state.

The persist state helps you to persist your data this means it helps hold the data in the store from clearing out before the page refreshes to  persist redux store data we have to install  the `redux-persist` package

```jsx
npm install redux-persist
```

It won't end here we just installed the package we now have to use, In using it we have to update just two files 

- Firstly our main.jsx or index.js file is located in the src folder, in this file, we have to import two things
    
    ```jsx
    import {PersistGate} from 'redux-persist/integration/react'
    import { persistStore } from 'redux-persist';
    ```
    
    After importing this we have to wrap the app component with the PersistGate, and the PersistGate has an attribute called the persistor, in this persistor we pass in the persistStore method, and then in the persistStore method we pass in what we want to persist which in our case is the store this is how your code will be
    
    ```jsx
    import React from 'react';
    import ReactDOM from 'react-dom/client';
    import './index.css';
    import App from './App';
    import { Provider } from 'react-redux';
    import { store } from './Store';
    import {PersistGate} from 'redux-persist/integration/react'
    import { persistStore } from 'redux-persist';
    
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(
      <React.StrictMode>
        <Provider store={store}>
          <PersistGate persistor={persistStore(store)}>
            <App />
          </PersistGate>
        </Provider>
      </React.StrictMode>
    );
    ```
    
- Secondly, in our store in the index.js file, we will also import two things
    
    ```jsx
    import storage from "redux-persist/lib/storage";
    import { persistReducer } from "redux-persist";
    ```
    
    after the import we set up the configuration where the data are going to be stored, this configuration holds three thing 
    
    ```jsx
    const config = {
        key: 'root', // this is the name of the storage
        version:1, // the version of the storage
        storage, // storage that was imported from the redux-persist/lib/storage
    }
    ```
    
    Now in your export instead of passing the combineReducers method into the createStore, we now pass in the persistReducer method into the createStore method.
    
    Now the persistReducer will receive the configuration  and the combineReducers, you can check out the snippet below
    
    ```jsx
    import {combineReducers ,createStore} from 'redux'
    import {TodoReducer}  from './Reducers/TodoReducer'
    import { UserReducer } from './Reducers/UserReducer'
    import storage from "redux-persist/lib/storage";
    import { persistReducer } from "redux-persist";
    const config = {
        key: 'root',
        version:1,
        storage,
    }
    
    export const store = createStore(
        persistReducer(config,combineReducers({TodoReducer,UserReducer}))
    );
    ```
    

Following these two simple steps after reloading the browser, you can see your data still remains

## Conclusion

Adding Redux (redux-toolkit ) to your reactjs project makes it easy for you to manage data across your react component as well as make your work look neat and professional.

It was awesome guiding you through you can get all the code snippets from my [GitHub repository](https://github.com/ebuberoderick/my-app-name) and I am also open to attending to any related questions or more clarification