Revolutionize Your React App with useReducer: Mastering State Management

Revolutionize Your React App with useReducer: Mastering State Management

Nov 13 2023

State management is at the core of any React application, and for more complex scenarios, the useReducer hook provides a powerful way to manage state in a structured manner. In this article, we'll explore useReducer through a concrete example: creating a to-do list.


Understanding useReducer

useReducer is a React hook that allows state management using a reducer pattern. Instead of using useState to manage a component's state, useReducer is particularly suitable for handling complex states, such as lists of data.

The basic idea is to provide a reducer function that takes two arguments: the current state and the action to perform.

  • The action is typically an object that describes a change in state, such as adding a task, deleting it, or marking it as done.
  • The reducer function returns the new state based on the current state and the action.

Pratical exemple : Creating a To-Do List with useReducer

Imagine you're developing a to-do list application. Here's how you can use useReducer to manage the list of tasks:

1import React, { useReducer } from 'react';
2
3// Define a reducer function
4const taskReducer = (state, action) => {
5  switch (action.type) {
6    case 'ADD_TASK':
7      return [...state, { id: Date.now(), text: action.text, done: false }];
8    case 'DELETE_TASK':
9      return state.filter(task => task.id !== action.id);
10    case 'TOGGLE_TASK':
11      return state.map(task =>
12        task.id === action.id ? { ...task, done: !task.done } : task
13      );
14    default:
15      return state;
16  }
17};
18
19function TaskList() {
20  // Replace useState by useReducer with reducer and initial state
21  const [tasks, dispatch] = useReducer(taskReducer, []);
22
23  // make tasks for the reducer
24  const addTask = text => {
25    dispatch({ type: 'ADD_TASK', text });
26  };
27
28  const deleteTask = id => {
29    dispatch({ type: 'DELETE_TASK', id });
30  };
31
32  const toggleTask = id => {
33    dispatch({ type: 'TOGGLE_TASK', id });
34  };
35
36  return (
37    <div>
38      <h1>To-Do List</h1>
39      <ul>
40        {tasks.map(task => (
41          <li key={task.id}>
42            <span
43              style={{ textDecoration: task.done ? 'line-through' : 'none' }}
44            >
45              {task.text}
46            </span>
47            <button onClick={() => toggleTask(task.id)}>
48              {task.done ? 'Undo' : 'Done'}
49            </button>
50            <button onClick={() => deleteTask(task.id)}>Delete</button>
51          </li>
52        ))}
53      </ul>
54      <input
55        type="text"
56        placeholder="Add a task"
57        onKeyUp={e => {
58          if (e.key === 'Enter' && e.target.value) {
59            addTask(e.target.value);
60            e.target.value = '';
61          }
62        }}
63      />
64    </div>
65  );
66}

In this example, we've created a to-do list application. We use useReducer to manage the tasks. Actions like ADD_TASK, DELETE_TASK, and TOGGLE_TASK allow us to modify the state of the task list in a structured way.


Benefits of useReducer for Task Management

useReducer brings several advantages for managing a to-do list in a React application:

  • Structure and Readability: Actions are explicitly defined with types, making the code more readable and maintainable.

  • Immutable State: useReducer encourages state immutability, which avoids side effects and unexpected errors.

  • Handling Complex States: useReducer is ideal for managing a list of data with many possible actions.

  • Separation of Concerns: By grouping actions and reduction logic in a single function, useReducer promotes the separation of concerns.

  • Potential for Future Extensions: You can easily add new actions to extend your application's functionality.


Conclusion

In conclusion, useReducer is a powerful tool for managing the state of a React application, especially when dealing with complex states and a variety of possible actions. By incorporating it into your projects, you can create more robust and structured applications while improving code maintainability and readability.

See more articles