Redux for React developers-The complete guide

Most react developers find redux as a complex and hard-to-learn concept. If I will be honest, for me also it was hard to grab in the beginning. There are reducers…There are actions…There are action creators…There is a redux store…There are redux middlewares…Lot’s of information to understand at once and it is a bit hard if you are not following it the right way. If you are not, You will be ended up hating redux. That’s why I thought, write this article for you. Then you can follow this one and learn it perfectly. Enough for side talk. Let’s jump into our topic. What we are going to learn here :

What is Redux?

Redux is a lightweight standalone javascript library, that can be used with any javascript framework and it is used with ReactJS frequently. That’s why most of the time we talk about it as React-redux. Simply, Redux is a state management tool that works as a “centralized store”. This is the only place to access the state.

Why do we need Redux?

For a small application, you can manage the state without using redux. But for larger applications, you have to use redux. When you are using redux with react, states will no longer need to be lifted up. This makes it easier for you to trace which causes any change. Applying redux to your application, you can build components that do not need any state or methods for its children components to share data among themselves. Everything will be handled by Redux which greatly simplifies the app and makes it easier to maintain. The main benefit of using Redux is this, but there are other advantages as well.

  • Redux makes the state predictable
  • Redux is maintainable
  • Debugging is easy in redux
  • Performance benefits
  • Ease of testing
  • State persistence
  • Sever-side rendering

What is the Redux store?

The store consists of the whole state tree of your application which is immutable. You can have only one store for your application. In simple words, the store is a just plain javascript object that allows components to share state.

What is action and action creator?

Action is also a simple object that has two properties as payload and action type. Since action types are strings, it is better to use a separate file to define them and uses whatever place you want. Action creator is a normal function that just returns as action. Making action creators is a wonderful idea since it gives you a method to create reusable actions that you can utilize across your whole code base. Additionally, you may insert any logic there that you would not want to have to recall each time you do an action.

What is a reducer?

Reducer is a function that takes an action and the previous state of the application and returns the new state based on the action type. The action describes what has happened in the application and it is the reducer’s job to return the new state based on that action. The function then uses a switch statement to identify the kind of action it is handling. In order to prevent the program from losing its present state, if there is an unknown action, it should return the current state. It has to be a pure function with no side effects. You can only have one reducer for your store. We call it a root reducer. But inside the root reducer, we can combine several reducers using combineReducers method.

What is middleware?

Every action that is passed to the reducer can be intercepted using Redux Middleware, allowing you to adjust or stop the action. You may make asynchronous requests, report errors, and much more with the use of middleware. Before the action is dispatched to the store, the middleware gets executed. Because we’re calling the next function inside the middleware by passing the action, the reducer will also be executed which results in the change in the store. Now, what will happen If we don’t call the next function inside the middleware? Then the action will not be sent to the reducer so the store will not be updated.

Redux devTool

This is a development time package that provides power-ups for your redux development workflow. Using redux devTool, you will be able to:

  • Inspect every state and action payload.
  • Go back in time by “canceling” actions.
  • Re-evaluated each “staged” action, if you change the reducer code.
  • If the reducers throw, you will see during which action this happened, and what the error was.

It may be used as a standalone app, a React component built inside the client app, or as a browser extension for Chrome, Edge, and Firefox. When you are creating the store you have to add the below middleware.

window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()

NPM packages that we need

After installing the redux boilerplate of your project you need some npm packages. First of all, need to install redux.

npm install redux

Then you need react-redux.

npm install react-redux

You can use redux-thunk as custom middleware.

npm install redux-thunk

Up to this point, I don’t think you have understood any of this. Most probably, now you are thinking what the hell is this man talking about? But that introduction is needed for later parts. After we did the coding parts using all of these concepts, you will understand well what I have talked about.

Then, let’s jump into the coding part. We are going to create a simple application with redux. Here, I will not go deep into the React part. I will mainly focus on the Redux side.

Let’s get a brief intro to what we are implementing.

  • create some actions for the application
  • dispatch actions in the components
  • create reducers
  • add reducers to root reducer
  • create the redux store
  • connect the store with the application
  • connect the store with the application
  • show the to-do list in another component

create some actions for the application

As I previously explained, before creating the action, it’s better if you define the action type in a separate file as constants.

constants/actionTypes.js

export const ADD_TODO = "ADD_TODO";
export const COMPLETE_TODO = "COMPLETE_TODO";
export const SHOW_ALL = "SHOW_ALL";
export const SHOW_ACTIVE = "SHOW_ACTIVE";
export const SHOW_COMPLETED = "SHOW_COMPLETED";
export const ADD_TODO_FAIL = "ADD_TODO_FAIL";
export const ADDING_START = "ADDING_START";

Though you don’t know how to create actions yet, I think you know what action is because of the previous explanation. I will explain this using only one main action. But you can practice this by adding new actions like in the actionTypes.

actions/Todo.js

export const addTodo = (input) => (dispatch) => {
dispatch({ type: ADDING_START });
try {
// here comes a API if you want this to save in database
dispatch({ type: ADD_TODO, data: input });
} catch (error) {
console.log(error);
dispatch({ type: ADD_TODO_FAIL });
}
};

This is the addTodo action creator with its action to add a new to-do item. Here I have gone a bit complex way. There are 3 actions in this creator. The main action is : dispatch({ type: ADD_TODO, data: input });

Now, how do we call this action creator in our components?

dispatch actions in the components

This is the react component that I have created to add new to-do items. When submitting the form action should be called which we created above.

import React, { useState } from "react";const AddTodo = () => {
const [input, setInput] = useState("");
const handleOnSubmit = (event) => {
event.preventDefault();
//submit action is here
};
return (
<div className="form">
<form onSubmit={handleOnSubmit}>
<input
value={input}
placeholder="Type here"
onChange={(event) => setInput(event.target.value)}
/>
<button type="submit">Add Todo</button>
</form>
</div>
);
};
export default AddTodo;

Need to import useDispatch from react-redux and dispatch the action.

import {useDispatch} from 'react-redux';
import { addTodo } from "../actions/Todo";
const dispatch = useDispatch();
const handleOnSubmit = (event) => {
event.preventDefault();
if (!input.trim()) {
return;
}
dispatch(addTodo(input));
setInput("");
};

Create reducers

As the next step, you need to create a reducer for your actions. Here, I am creating the reducer called todoReducer in reducers folder. In this reducer function, the current state and action will be the parameters. We can put the type of action into switch and update the state according to that.

import { ADDING_START, ADD_TODO, ADD_TODO_FAIL } from "../constants/ActionType";const todoReducer = (
state = { todoData: [], loading: false, error: false },
action
) => {
switch (action.type) {
case ADDING_START:
return {...state, loading: true};
case ADD_TODO:
return {...state, todoData:[...state.todoData, action.data], loading: false}
case ADD_TODO_FAIL:
return {...state, error: true}
default:
return state;
}
};
export default todoReducer;

Add reducers to the root reducer

As I already mentioned above, you can not add several reducers to the redux store. So, we create therootreducer and combine that with the redux store.

import { combineReducers } from "redux";
import todoReducer from "./TodoReducers";
export const rootReducer = combineReducers({
todoReducers: todoReducer
});

Here, we can use combineReducers from redux .

Create the Redux store

This is the most important part of the process. But this is pretty simple and the funny part is you don’t need to create this again and again when you create another application. You can use the same code base for any application as your redux store.

import {
legacy_createStore as createStore,
applyMiddleware,
compose,
} from "redux";
import { rootReducer } from "./reducers";
import thunk from "redux-thunk";
const middleware = [thunk];
const initialState = {};const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleware),
window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__()
)
);

Connect the store with the application

Just creating the store is not enough. You need to connect the store with your application. You have to do some changes to index.js file like this. Add Provider from the react-redux .

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';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);

If you did the coding part up to this point you can test the application using redux devTool. Your to-do list will be in the store.

Then you can show this data easily using another component. This part is very simple. Since you can access the redux store anywhere in the application as below.

const todoList = useSelector((state) => state.todoReducer.todoData);

You have to import useSelector from react-redux .

Show the to-do list in another component

import React from "react";
import { useSelector } from "react-redux";
const ViewTodo = () => {
const todoList = useSelector((state) => state.todoReducer.todoData);
return (
<div>
<ul>
{todoList.map((todo) => (
<li key={todo}>{todo}</li>
))}
</ul>
</div>
);
};
export default ViewTodo;

This will be the output of the simple application. Now you can play with this and get familiar. Before concluding the article I am gonna point out an important factor that you will definitely need.

Maybe, You already know that the to-do list will disappear from the display as well as from the redux store(you can see it from devTool), when the browser refresh. The reason is, refreshing the browser will bring the state to its initial state. The initial state is an empty object. That's why it disappears.

I will show a solution for this using sessionStorage of the browser. You can load the initial state from the sessionStorage and when the state is changed sessionStorage also should update.

With these changes, this is the code for the store.

This is the end of our article. We have discussed all the theory parts about redux and after we build an actual application. Hope this will be helpful for you. You can refer GitHub rep of this application. you will find this application with more functionalities.

See you in the next blog post. Bye Bye🍻🍸❤️❤️

--

--

Undergraduate of University of Moratuwa | Faculty of Information Technology

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Kushan Madhusanka

Undergraduate of University of Moratuwa | Faculty of Information Technology