> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/preactjs/preact/llms.txt
> Use this file to discover all available pages before exploring further.

# useReducer

> An alternative to useState for complex state logic

`useReducer` is an alternative to `useState` for managing complex state logic. It's usually preferable when you have state that involves multiple sub-values or when the next state depends on the previous one in complex ways.

## Signature

```typescript theme={null}
function useReducer<S, A>(
  reducer: (prevState: S, action: A) => S,
  initialState: S
): [S, Dispatch<A>]

function useReducer<S, A, I>(
  reducer: (prevState: S, action: A) => S,
  initialArg: I,
  init: (arg: I) => S
): [S, Dispatch<A>]
```

## Parameters

<ParamField path="reducer" type="(prevState: S, action: A) => S" required>
  A function that takes the current state and an action, and returns the new state. The reducer should be a pure function.
</ParamField>

<ParamField path="initialState" type="S" required>
  The initial state value (when using the two-parameter signature).
</ParamField>

<ParamField path="initialArg" type="I" required>
  The initial argument passed to the `init` function (when using the three-parameter signature).
</ParamField>

<ParamField path="init" type="(arg: I) => S" optional>
  A function that receives `initialArg` and returns the initial state. Useful for lazy initialization or deriving initial state from props.
</ParamField>

## Returns

Returns a tuple containing:

1. **Current state** (`S`): The current state value
2. **Dispatch function** (`Dispatch<A>`): A function to dispatch actions to the reducer

## Basic Usage

```jsx theme={null}
import { useReducer } from 'preact/hooks';

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, { 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>
  );
}
```

## With Action Payloads

```jsx theme={null}
function reducer(state, action) {
  switch (action.type) {
    case 'add-item':
      return {
        ...state,
        items: [...state.items, action.payload]
      };
    case 'remove-item':
      return {
        ...state,
        items: state.items.filter(item => item.id !== action.payload.id)
      };
    case 'update-item':
      return {
        ...state,
        items: state.items.map(item =>
          item.id === action.payload.id ? action.payload : item
        )
      };
    default:
      return state;
  }
}

function TodoList() {
  const [state, dispatch] = useReducer(reducer, { items: [] });

  const addTodo = (text) => {
    dispatch({
      type: 'add-item',
      payload: { id: Date.now(), text }
    });
  };

  return (
    <div>
      {state.items.map(item => (
        <div key={item.id}>
          {item.text}
          <button onClick={() => dispatch({ type: 'remove-item', payload: item })}>
            Remove
          </button>
        </div>
      ))}
    </div>
  );
}
```

## Lazy Initialization

```jsx theme={null}
function init(initialCount) {
  // Expensive computation only runs once
  return {
    count: initialCount,
    history: [initialCount]
  };
}

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      const newCount = state.count + 1;
      return {
        count: newCount,
        history: [...state.history, newCount]
      };
    case 'reset':
      return init(action.payload);
    default:
      return state;
  }
}

function Counter({ initialCount }) {
  const [state, dispatch] = useReducer(reducer, initialCount, init);

  return (
    <div>
      <p>Count: {state.count}</p>
      <p>History: {state.history.join(', ')}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'reset', payload: 0 })}>Reset</button>
    </div>
  );
}
```

## Complex State Management

```jsx theme={null}
const initialState = {
  user: null,
  loading: false,
  error: null,
  data: []
};

function reducer(state, action) {
  switch (action.type) {
    case 'fetch-start':
      return { ...state, loading: true, error: null };
    case 'fetch-success':
      return {
        ...state,
        loading: false,
        data: action.payload
      };
    case 'fetch-error':
      return {
        ...state,
        loading: false,
        error: action.payload
      };
    case 'set-user':
      return { ...state, user: action.payload };
    case 'logout':
      return { ...initialState };
    default:
      return state;
  }
}

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

  const fetchData = async () => {
    dispatch({ type: 'fetch-start' });
    try {
      const response = await fetch('/api/data');
      const data = await response.json();
      dispatch({ type: 'fetch-success', payload: data });
    } catch (error) {
      dispatch({ type: 'fetch-error', payload: error.message });
    }
  };

  return <div>{/* ... */}</div>;
}
```

## Passing Dispatch Down

```jsx theme={null}
function reducer(state, action) {
  switch (action.type) {
    case 'toggle':
      return { ...state, [action.payload]: !state[action.payload] };
    default:
      return state;
  }
}

function DeepChild({ dispatch, id }) {
  // Child can dispatch without callbacks
  return (
    <button onClick={() => dispatch({ type: 'toggle', payload: id })}>
      Toggle
    </button>
  );
}

function Parent() {
  const [state, dispatch] = useReducer(reducer, {
    item1: false,
    item2: false
  });

  return (
    <div>
      <DeepChild dispatch={dispatch} id="item1" />
      <DeepChild dispatch={dispatch} id="item2" />
    </div>
  );
}
```

<Note>
  `useReducer` is usually preferable to `useState` when:

  * You have complex state logic involving multiple sub-values
  * The next state depends on the previous state in non-trivial ways
  * You want to optimize performance for components with deep updates by passing `dispatch` down instead of callbacks
</Note>

<Note>
  The reducer function should be pure: given the same inputs, it should always return the same output. Don't perform side effects in reducers.
</Note>

<Note>
  If you dispatch an action that results in the same state value (compared using `Object.is`), Preact will skip re-rendering the component and its children.
</Note>
