React useReducer Hook

The useReducer hook is an alternative to useState for managing more complex state logic in React functional components. It is especially useful when the state depends on multiple actions or when state transitions are complex. The useReducer hook uses a reducer function to manage state updates, similar to how reducers work in Redux.


1. Basic Counter Example using useReducer Hook

In this example, we create a simple counter component using useReducer. The reducer function will handle two actions: increment and decrement. This example demonstrates the basic setup of the hook.

</>
Copy
import React, { useReducer } from 'react';

function reducer(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(reducer, { count: 0 }); // Initial state

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

export default Counter;

Explanation:

  • reducer: A function that takes the current state and an action, then returns the updated state.
  • useReducer: Initializes the state and provides a dispatch function to trigger actions.
  • When user clicks on Increment button, dispatch({ type: 'increment' }) is called, and this sends an action to the reducer to update the state.
  • When user clicks on Decrement button, dispatch({ type: 'decrement' }) is called, and this sends an action to the reducer to update the state.

Output:


2. Example: Form State Management using useReducer Hook

In this example, we use useReducer to manage the state of a form with multiple fields. The reducer function handles updates to each field, making the code more organized compared to using multiple useState hooks.

</>
Copy
import React, { useReducer } from 'react';

function reducer(state, action) {
  return {
    ...state,
    [action.field]: action.value,
  };
}

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

  const handleChange = (e) => {
    dispatch({ field: e.target.name, value: e.target.value });
  };

  return (
    <div>
      <label>
        Name:
        <input type="text" name="name" value={state.name} onChange={handleChange} />
      </label>
      <br />
      <label>
        Email:
        <input type="email" name="email" value={state.email} onChange={handleChange} />
      </label>
      <br />
      <p>Name: {state.name}</p>
      <p>Email: {state.email}</p>
    </div>
  );
}

export default Form;

Explanation:

When user clicks on any of the inputs, handleChange function is called, which calls dispatch, which in turn sends an action to the reducer function.

  • reducer: Updates the specific field in the state based on the action.
  • dispatch: Handles updates to each input field dynamically.
  • This approach scales better than managing each input with separate useState hooks.

Output:


3. Example: Todo List with Add and Remove using useReducer Hook

In this example, we build a simple todo list where items can be added and removed. The reducer function handles the add and remove actions, and useReducer manages the list state.

</>
Copy
import React, { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'add':
      return [...state, { id: Date.now(), text: action.text }];
    case 'remove':
      return state.filter(todo => todo.id !== action.id);
    default:
      return state;
  }
}

function TodoList() {
  const [state, dispatch] = useReducer(reducer, []);
  const [text, setText] = React.useState('');

  const handleAdd = () => {
    dispatch({ type: 'add', text });
    setText('');
  };

  return (
    <div>
      <input
        type="text"
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="Enter a todo"
      />
      <button onClick={handleAdd}>Add</button>
      <ul>
        {state.map(todo => (
          <li key={todo.id}>
            {todo.text}
            <button onClick={() => dispatch({ type: 'remove', id: todo.id })}>Remove</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default TodoList;

Explanation:

  • reducer: Handles add and remove actions to update the todo list state.
  • dispatch: Adds new todos or removes existing ones based on the action type.
  • The list dynamically updates as items are added or removed, demonstrating the power of useReducer for list management.

Output:


Conclusion

The useReducer hook is a versatile tool for managing complex state logic in React components. It is particularly helpful when you need to handle multiple related state transitions or actions. By using a reducer function, you can keep your state management logic clean and organized. Start practicing with useReducer to simplify state management in your React projects!