JAVASCRIPT

Manage Complex Component State with useReducer

Discover how to centralize and manage more intricate state logic in React components using the useReducer hook, ideal for scenarios with multiple related state transitions.

import React, { useReducer } from 'react';

// 1. Define the reducer function
function todoReducer(state, action) {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        { id: Date.now(), text: action.payload, completed: false },
      ];
    case 'TOGGLE_TODO':
      return state.map((todo) =>
        todo.id === action.payload
          ? { ...todo, completed: !todo.completed }
          : todo
      );
    case 'REMOVE_TODO':
      return state.filter((todo) => todo.id !== action.payload);
    default:
      throw new Error();
  }
}

function TodoApp() {
  // 2. Initialize useReducer
  const [todos, dispatch] = useReducer(todoReducer, []); // [] is the initial state
  const [newTodoText, setNewTodoText] = React.useState('');

  const handleAddTodo = () => {
    if (newTodoText.trim()) {
      dispatch({ type: 'ADD_TODO', payload: newTodoText });
      setNewTodoText('');
    }
  };

  return (
    <div>
      <h1>Todo List</h1>
      <input
        type="text"
        value={newTodoText}
        onChange={(e) => setNewTodoText(e.target.value)}
        placeholder="Add a new todo"
      />
      <button onClick={handleAddTodo}>Add Todo</button>
      <ul>
        {todos.map((todo) => (
          <li key={todo.id} style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
            {todo.text}
            <button onClick={() => dispatch({ type: 'TOGGLE_TODO', payload: todo.id })}>
              {todo.completed ? 'Undo' : 'Complete'}
            </button>
            <button onClick={() => dispatch({ type: 'REMOVE_TODO', payload: todo.id })}>
              Remove
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default TodoApp;
How it works: This snippet illustrates the `useReducer` hook, a powerful alternative to `useState` for managing more complex state logic, especially when state transitions depend on the previous state or involve multiple sub-values. It centralizes state management in a single reducer function, making it more predictable and easier to debug. The `todoReducer` function takes the current state and an action, returning a new state based on the action type. The `dispatch` function is then used within the component to trigger state updates by sending actions to the reducer.

Need help integrating this into your project?

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

Hire DigitalCodeLabs