Tutorials Logic, IN info@tutorialslogic.com

React useReducer State Management Pattern

What Is useReducer?

useReducer is a React hook used to manage state when update logic becomes more structured or complex. Instead of updating values directly with a setter, you dispatch actions and let a reducer function decide how the next state should look.

This pattern is helpful when many actions can affect the same state, when several state fields belong together, or when you want state transitions to be easier to read and test.

useState vs useReducer

Feature useState useReducer
Best for Simple independent values Complex or related state
Update style Call setter directly Dispatch actions
Logic location Usually inside component handlers Centralized in reducer function
Readability Great for simple cases Better when many transitions exist

How a Reducer Works

A reducer is a function that receives the current state and an action object, then returns the next state. The component does not directly change values. It only dispatches actions such as increment, reset, or remove.

Basic Example

Counter with useReducer

Counter with useReducer
function counterReducer(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
    }
}

Basic Example - JSX Example

Basic Example - JSX Example
import { useReducer } from 'react'

function counterReducer(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(counterReducer, { count: 0 })

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

Why useReducer Is Useful

  • It keeps update logic in one place
  • It works well when many actions affect the same state
  • It makes transitions easier to read in larger components
  • Reducer functions are easier to test because they are plain functions

Todo Example

Todo App with useReducer

Todo App with useReducer
import { useReducer, useState } from 'react'

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] = useReducer(todoReducer, [])
    const [input, setInput] = useState('')

    function addTodo() {
        if (!input.trim()) return
        dispatch({ type: 'add', text: input })
        setInput('')
    }

    return (
        <div>
            <input value={input} onChange={e => setInput(e.target.value)} placeholder="New task" />
            <button onClick={addTodo}>Add</button>
            <ul>
                {todos.map(todo => (
                    <li key={todo.id}>
                        {todo.text}
                        <button onClick={() => dispatch({ type: 'remove', id: todo.id })}>Remove</button>
                    </li>
                ))}
            </ul>
        </div>
    )
}

Form State Example

Reducers are also useful when a form has several related fields and multiple possible actions such as update, reset, and submit.

Form State Example - JSX Example

Form State Example - JSX Example
import { useReducer } from 'react'

function formReducer(state, action) {
    switch (action.type) {
        case 'update_field':
            return {
                ...state,
                [action.field]: action.value
            }
        case 'reset':
            return { name: '', email: '' }
        default:
            return state
    }
}

When to Use useReducer

  • Use useState for simple values like a toggle or one input field
  • Use useReducer when many actions affect the same state
  • Use useReducer when multiple fields belong together
  • Use useReducer when state transitions should be explicit and testable

Reducer Failure Cases

Mistake Why it is a problem Better approach
Using useReducer for very simple state Adds extra ceremony with little benefit Use useState for simple cases
Writing reducers that mutate state Breaks predictable updates Return a new state object or array
Using unclear action names Makes reducer logic hard to follow Use descriptive action types like add_todo or reset_form
Placing too much unrelated logic inside one reducer Creates a large hard-to-maintain reducer Keep reducers focused or split responsibilities

Best Practices

  • Use descriptive action objects
  • Keep reducers pure and predictable
  • Return new objects and arrays instead of mutating state
  • Choose useReducer when it improves clarity, not by default
  • Test reducer functions independently when the logic becomes important

Summary

useReducer is a strong choice when component state has multiple transitions or related fields. It centralizes state logic, makes updates easier to reason about, and scales better than scattered state handlers when the logic becomes more complex.

Before you move on

React useReducer State Management Pattern Mastery Check

4 checks
  • useReducer is a React hook used to manage state when update logic becomes more structured or complex.
  • Instead of updating values directly with a setter, you dispatch actions and let a reducer function decide how the next state should look.
  • A reducer is a function that receives the current state and an action object, then returns the next state.
  • The component does not directly change values.
Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.