techStackGuru

React useReducer Hook


In React, useReducer is a powerful hook that allows you to manage complex states and state transitions. Compared to the useState hook, it offers more control and flexibility.

There are two arguments to the useReducer hook: a reducer function and an initial state. By using the reducer function, we can specify how state should be updated depending on the action taken. As arguments, it receives the current state and a new action object. In a state, the initial state represents the starting point.

A reducer function is invoked when an action is dispatched, along with the state and the action object. You can update the state of the reducer based on the action type you examine inside the reducer. In order to maintain immutability, the reducer function should always return a new state object.

Counter with Increment and Decrement:

import React, { useReducer } from 'react';

const initialState = 0;

const reducer = (state, action) => {
  switch (action.type) {
    case 'increment':
      return state + 1;
    case 'decrement':
      return state - 1;
    case 'reset':
      return initialState;
    default:
      return state;
  }
};

const Counter = () => {
  const [count, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
      <button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
    </div>
  );
};

export default Counter; 

As shown in the example, the Counter component uses the useReducer hook to manage a count variable. A reducer function defines how to update the state based on different actions based on the initialState.

Reducer functions take two parameters: the state (current state) and the action (the change that needs to be made). Depending on the action.type, the state of the reducer is determined with a switch statement.

Theme Toggler:

import React, { useReducer } from 'react';

const initialState = { theme: 'light' };

const reducer = (state, action) => {
  switch (action.type) {
    case 'toggle':
      return { theme: state.theme === 'light' ? 'dark' : 'light' };
    default:
      throw new Error();
  }
};

const ThemeToggler = () => {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <button onClick={() => dispatch({ type: 'toggle' })}>
        Toggle Theme
      </button>
      <div className={state.theme}>
        {state.theme === 'light' ? 'Light Theme' : 'Dark Theme'}
      </div>
    </div>
  );
}; 

With the useReducer hook, the ThemeToggler component initializes the state with the initialState and provides access to the state and dispatch function. Reducers receive actions via the dispatch function.

Upon clicking the "Toggle Theme" button, the dispatch function is called with the action object [ type: 'toggle']. As a result, the reducer handles the action and updates the state.

JSX is rendered dynamically according to state.theme value by applying className. Depending on the theme, it displays either "Light Theme" or "Dark Theme".