JAVASCRIPT

Manage Complex State with `useReducer` Hook

Efficiently manage intricate state logic in React components using the `useReducer` hook. This snippet demonstrates its power for handling multiple state transitions cleanly, providing a predictable state container pattern similar to Redux.

import React, { useReducer } from 'react';

// 1. Define initial state
const initialState = {
  count: 0,
  text: 'Hello Reducer',
  items: [],
};

// 2. Define a reducer function
const reducer = (state, action) => {
  switch (action.type) {
    case 'increment':
      return { ...state, count: state.count + 1 };
    case 'decrement':
      return { ...state, count: state.count - 1 };
    case 'reset':
      return { ...state, count: initialState.count };
    case 'setText':
      return { ...state, text: action.payload };
    case 'addItem':
      return { ...state, items: [...state.items, action.payload] };
    case 'removeItem':
      return { ...state, items: state.items.filter(item => item !== action.payload) };
    default:
      throw new Error('Unknown action type');
  }
};

// 3. Create a component that uses useReducer
function CounterWithReducer() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div style={{ padding: '20px', border: '1px solid #ccc', borderRadius: '5px' }}>
      <h2>Count: {state.count}</h2>
      <button onClick={() => dispatch({ type: 'increment' })} style={{ marginRight: '10px' }}>Increment</button>
      <button onClick={() => dispatch({ type: 'decrement' })} style={{ marginRight: '10px' }}>Decrement</button>
      <button onClick={() => dispatch({ type: 'reset' })}>Reset Count</button>

      <h2 style={{ marginTop: '20px' }}>Text: {state.text}</h2>
      <input
        type="text"
        value={state.text}
        onChange={(e) => dispatch({ type: 'setText', payload: e.target.value })}
        style={{ padding: '8px', width: '300px' }}
      />

      <h2 style={{ marginTop: '20px' }}>Items</h2>
      <button onClick={() => dispatch({ type: 'addItem', payload: `Item ${state.items.length + 1}` })}>Add Item</button>
      <ul style={{ listStyleType: 'disc', paddingLeft: '20px' }}>
        {state.items.map((item, index) => (
          <li key={index} style={{ margin: '5px 0' }}>
            {item}
            <button onClick={() => dispatch({ type: 'removeItem', payload: item })} style={{ marginLeft: '10px', background: '#dc3545', color: 'white', border: 'none', borderRadius: '3px', padding: '5px 10px', cursor: 'pointer' }}>
              Remove
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default CounterWithReducer;
How it works: The `useReducer` hook is an alternative to `useState` for managing more complex state logic that involves multiple sub-values or when the next state depends on the previous one. It takes a reducer function and an initial state, returning the current state and a `dispatch` function. The `dispatch` function is used to send 'actions' to the reducer, which then computes the new state based on the action type and payload. This pattern promotes predictable state changes and is particularly useful for state transitions that are coupled or require specific sequences, making your state management more organized and testable than deeply nested `useState` calls.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs