useReducer Hook

Loading

The useReducer hook is a React hook that provides an alternative to useState for managing state in a React component. It is typically used when state logic is complex, or when the state depends on the previous state. It is commonly used for managing state in larger applications or in situations where multiple state transitions need to be handled in a predictable and structured way, such as in forms, complex stateful logic, or managing global state in a component.

1. What is the useReducer Hook?

The useReducer hook is very similar to useState, but it provides more control over state transitions by using a reducer function. It follows the same pattern as Redux, where actions are dispatched to update the state. Instead of directly mutating the state, useReducer uses a reducer function that returns a new state based on the action dispatched.

Basic Syntax of useReducer:

const [state, dispatch] = useReducer(reducer, initialState);
  • state: The current state of the component.
  • dispatch: A function that sends actions to the reducer.
  • reducer: A function that takes the current state and an action, and returns the next state.
  • initialState: The initial state value.

2. Using useReducer

Example: Basic Counter with useReducer

import React, { useReducer } from 'react';

// Reducer function
const counterReducer = (state, action) => {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      return state;
  }
};

function Counter() {
  const [state, dispatch] = useReducer(counterReducer, { count: 0 });

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

export default Counter;

In this example:

  • counterReducer is a function that receives the current state and an action, and returns a new state.
  • The dispatch function sends an action to the reducer to update the state.

3. Understanding the Reducer Function

A reducer function is a pure function that receives two arguments:

  • State: The current state.
  • Action: An object representing the action to be performed, which typically has a type property and can include additional data (payload).

The reducer function returns the updated state based on the action’s type.

Example: Reducer with Payload

const reducer = (state, action) => {
  switch (action.type) {
    case 'setName':
      return { ...state, name: action.payload };
    default:
      return state;
  }
};

function App() {
  const [state, dispatch] = useReducer(reducer, { name: '' });

  return (
    <div>
      <p>Name: {state.name}</p>
      <button onClick={() => dispatch({ type: 'setName', payload: 'John' })}>
        Set Name
      </button>
    </div>
  );
}

Here:

  • The action type: 'setName' updates the name property in the state.
  • The payload carries the new name.

4. When to Use useReducer vs useState

  • useState: Great for simpler state logic where the state change is relatively straightforward, and it doesn’t involve complex transitions.
  • useReducer: Better when:
    • The state logic is more complex (e.g., dependent on previous state).
    • You need to manage multiple state variables that are related.
    • You want to centralize your state updates in a single function (the reducer).
    • You have complex state updates involving different actions and payloads.

5. Using useReducer with Multiple Actions

In real applications, you might need to handle different kinds of actions. useReducer can be extended to handle multiple action types, making it more scalable for complex state management.

Example: Handling Multiple Actions

import React, { useReducer } from 'react';

const initialState = { count: 0, text: '' };

// Reducer function to handle multiple actions
const reducer = (state, action) => {
  switch (action.type) {
    case 'increment':
      return { ...state, count: state.count + 1 };
    case 'decrement':
      return { ...state, count: state.count - 1 };
    case 'setText':
      return { ...state, text: action.payload };
    default:
      return state;
  }
};

function App() {
  const [state, dispatch] = useReducer(reducer, initialState);

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

      <p>Text: {state.text}</p>
      <input
        type="text"
        value={state.text}
        onChange={(e) => dispatch({ type: 'setText', payload: e.target.value })}
      />
    </div>
  );
}

export default App;

In this example:

  • The state is updated based on multiple action types: increment, decrement, and setText.
  • Each action type triggers a different update to the state.

6. useReducer with useContext for Global State

useReducer can also be used in combination with useContext to manage global state across your React application.

Example: Using useReducer with useContext

import React, { useReducer, useContext } from 'react';

// Create context
const GlobalStateContext = React.createContext();

// Reducer function
const globalReducer = (state, action) => {
  switch (action.type) {
    case 'toggleTheme':
      return { ...state, theme: state.theme === 'light' ? 'dark' : 'light' };
    default:
      return state;
  }
};

function App() {
  const [state, dispatch] = useReducer(globalReducer, { theme: 'light' });

  return (
    <GlobalStateContext.Provider value={{ state, dispatch }}>
      <ThemeSwitcher />
    </GlobalStateContext.Provider>
  );
}

function ThemeSwitcher() {
  const { state, dispatch } = useContext(GlobalStateContext);

  return (
    <div>
      <p>Current Theme: {state.theme}</p>
      <button onClick={() => dispatch({ type: 'toggleTheme' })}>Toggle Theme</button>
    </div>
  );
}

export default App;

In this example:

  • useReducer is used to manage the theme state.
  • useContext is used to provide and consume the state globally across components.

Leave a Reply

Your email address will not be published. Required fields are marked *