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.