← Back to Chapters

useReducer()

⚛️ useReducer()

? Quick Overview

The useReducer() Hook is an alternative to useState() used for handling complex, multi-step, or interdependent state logic in React applications.

It follows a reducer-based pattern similar to Redux, where actions describe events and a reducer decides how state changes.

? Key Concepts

  • Best suited for complex state logic
  • State updates depend on previous state
  • Centralized and predictable updates
  • Uses actions instead of direct setters

? Syntax / Theory

? View Code Example
// useReducer hook basic syntax
const [state, dispatch] = useReducer(reducer, initialState);
? View Code Example
// Reducer function handling different actions
function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
return state;
}
}

? Example 1: Simple Counter

? View Code Example
// Counter component using useReducer
import React, { useReducer } from "react";

const initialState = { count: 0 };

function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
case "reset":
return { count: 0 };
default:
return state;
}
}

function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);

return (
<div>
<h4>Count: {state.count}</h4>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
<button onClick={() => dispatch({ type: "reset" })}>Reset</button>
</div>
);
}

export default Counter;

The dispatch() function sends actions to the reducer, which returns the updated state.

? Example 2: Form State Management

? View Code Example
// Reducer managing multiple form fields
function formReducer(state, action) {
return {
...state,
[action.field]: action.value
};
}

function FormExample() {
const [form, dispatch] = React.useReducer(formReducer, { name: "", email: "" });

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

return (
<div>
<input name="name" value={form.name} onChange={handleChange} />
<input name="email" value={form.email} onChange={handleChange} />
<h6>Hello {form.name || "Guest"}</h6>
</div>
);
}

⚙️ Example 3: Todo List Reducer

? View Code Example
// Todo reducer with add and remove actions
function todoReducer(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 TodoApp() {
const [todos, dispatch] = React.useReducer(todoReducer, []);
return null;
}

? useReducer() vs useState()

  • useState: Simple, isolated state
  • useReducer: Complex, structured state logic

? Tips & Best Practices

  • Reducers must be pure functions
  • Keep action types descriptive
  • Group related state together
  • Combine with useContext for global state

? Try It Yourself

  1. Create a shopping cart reducer
  2. Build a login form reducer
  3. Track min and max values in a counter
  4. Implement global state using useReducer + useContext