Using Redux in React Applications

Page content

Hello everyone,

State management is one of the key concepts when it comes to developing applications using React. Redux is one of the popular state management solutions out there that works on the principle of storing the entire state of the application in a single central store. This makes it possible for all components to access the central store and removes the need to pass parameters and props between components. The concept is also referred to as the

single source of truth

The main building blocks of Redux are its actions, reducers, and store.

  • Actions - Events or messages sent to the store with the intended change

  • Reducers - Take in the messages, update the store by applying changes based on the action type

  • Store - Stores the state information

So let’s dive into an example that implements Redux for a ReactJS based web application.

Create a new project using the command

npx create-react-app using-redux-in-react
cd using-redux-in-react

Install required dependencies

yarn add react-redux redux

Create action

Create an action that adds an item to cart

export function addItem(item) {
  return {
    type: 'ADD_ITEM', item
  }
};

Create reducer

Create a reducer that will define the initialState that will act as the default state if there no changes. Redux will run all the reducers anytime you dispatch an action. Here, the important part is we are not directly modifying the state. Instead, we are creating a new array by spreading the old array and adding a new value.

const defaultCart = [
  {
    name: 'groceries'
  }
];

const cartReducer = (state = defaultCart, action) => {
  switch (action.type) {
    case 'ADD_ITEM':
      return [...state, {
           name: action.item
        } 
      ];
    default:
      return state;
  }
} 

export default cartReducer;

Initialize the store

The final step is to initialize your store. Here we will make use of a helper function combineReducers that helps produce a single reducing function you can eventually pass to createStore.

import {combineReducers, createStore} from 'redux';

import cartReducer from './reducers/cartReducer';

const rootReducer = combineReducers({cart: cartReducer});

function configureStore(state = { cart: [{name: 'groceries'}]}) {
  return createStore(rootReducer, state);
};

export default configureStore;

Putting it all together

We will create a simple form that will add our items to the cart. We will use the default event handlers to dispatch our Redux actions and update the state.

App.js


import './App.css';
import React, {useState} from 'react';
import {useDispatch, useSelector} from 'react-redux';
import {addItem} from './actions/addItemAction';

function App() {
  const [item, setItem] = useState('');
  
  // sorting the cart items alphabetically
  const items = [...useSelector(state => state.cart)].sort((a, b) => {
    return a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1;
  });

  const dispatch = useDispatch();

  const handleSubmit = event => {
    event.preventDefault();
    dispatch(addItem(item))
    setItem('');
  };

  return (
    <div className="wrapper">
      <h1>Item List</h1>
      <form onSubmit={handleSubmit}>
        <label>
          <p>
            Add Item
          </p>
          <input
            type="text"
            onChange={e => setItem(e.target.value)}
            value={item}
          />
        </label>
        <div>
          <button type="submit">Add</button>
        </div>
      </form>
      <ul>
        {items.map(item => (
          <li key={item.name}>
            <h3>{item.name}</h3>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default App;

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { Provider } from 'react-redux';
import configureStore from './store';

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

reportWebVitals();

Output screenshots

react-redux-output-1

react-redux-output-2

react-redux-output-3

react-redux-output-4

As seen in the above implementation there is a lot of boilerplate code involved in when using Redux which is not an ideal solution. In addition, even a minor change in Redux triggers the DOM restructuring process. This may affect the performance of the application in the long run.

In my upcoming post, I will talk about using the Redux toolkit which helps to reduce the boilerplate code if at all you plan to use Redux only as your preferred state management solution.

Personally, I feel that the new React Context API looks promising and is worth the try if you are planning to implement state management from scratch in your React based application.