How to Update Redux State in React

Managing global state in React is streamlined using Redux, specifically through its modern implementation, Redux Toolkit. This article provides a straightforward guide on how to update the Redux state in a React application by creating a state slice, defining reducer functions, and dispatching actions directly from your React components using hooks.

Step 1: Create a Redux Slice

The modern and recommended way to manage Redux state is through Redux Toolkit’s createSlice function. A slice allows you to define your initial state and the reducer functions that specify how the state updates in response to actions.

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

const counterSlice = createSlice({
  name: 'counter',
  initialState: { value: 0 },
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
    incrementByAmount: (state, action) => {
      state.value += action.payload;
    },
  },
});

export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;

In Redux Toolkit, you can write “mutating” logic inside reducers because it uses the Immer library under the hood to safely update the state immutably.

Step 2: Configure the Store

Once your reducer is created, you need to add it to your Redux store so the React application can access and update it.

import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

Step 3: Dispatch Actions from React Components

To update the Redux state from a React component, you use the useDispatch hook from the react-redux library. This hook returns a reference to the dispatch function, which you use to send actions to the Redux store.

Here is how you dispatch the slice actions in a component:

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement, incrementByAmount } from './counterSlice';

export function Counter() {
  // Read state from the store
  const count = useSelector((state) => state.counter.value);
  
  // Get the dispatch function
  const dispatch = useDispatch();

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={() => dispatch(increment())}>
        Increment
      </button>
      <button onClick={() => dispatch(decrement())}>
        Decrement
      </button>
      <button onClick={() => dispatch(incrementByAmount(5))}>
        Add 5
      </button>
    </div>
  );
}

Summary of the Update Flow

  1. User Interaction: A user clicks a button in the React component.
  2. Dispatch Action: The component calls dispatch(action()) (e.g., dispatch(increment())).
  3. Run Reducer: Redux sends the action to the corresponding reducer function inside the slice.
  4. Update State: The reducer updates the state.
  5. Re-render Component: The useSelector hook detects the state change and automatically re-renders the component with the new data.