# useDispatch Hook in React vs. Traditional Dispatch Function: Key Differences and Use Cases

> Explore useDispatch hook vs traditional dispatch in React Redux. Understand component local vs global state management. Optimize your app's state updates.

- Repository: [Meta/react](https://github.com/facebook/react)
- Tags: deep-dive
- Published: 2026-02-16

---

**The `useDispatch` hook in React Redux provides global store access for application-wide state management, while the traditional `dispatch` function from `useReducer` handles component-local state updates within React's fiber architecture.**

When building React applications with Redux for state management, understanding the distinction between these two dispatch mechanisms is critical for architectural decisions. The traditional dispatch function originates from React's core hooks system in the `facebook/react` repository, whereas `useDispatch` lives in the `reduxjs/react-redux` package and serves as a bridge to Redux's external store.

## Architectural Overview: Local vs. Global State

The fundamental difference lies in scope and implementation architecture:

| Aspect | Traditional Dispatch (`useReducer`) | React-Redux `useDispatch` |
|--------|-------------------------------------|---------------------------|
| **Origin** | React core hooks ([`ReactHooks.js`](https://github.com/facebook/react/blob/main/ReactHooks.js)) | React-Redux library ([`useDispatch.ts`](https://github.com/facebook/react/blob/main/useDispatch.ts)) |
| **Scope** | Component-local state | App-wide global store |
| **State Location** | React fiber internal state | External Redux store object |
| **Implementation** | Calls `dispatcher.useReducer` via `ReactSharedInternals.H` | Reads store from `ReactReduxContext` and returns `store.dispatch` |
| **Middleware Support** | None (synchronous reducer only) | Full middleware pipeline (thunks, sagas, etc.) |
| **Return Type** | `Dispatch<A>` (action type specific to reducer) | `Dispatch<AnyAction>` (any action store understands) |

### Traditional Dispatch in React Hooks

In [`packages/react/src/ReactHooks.js`](https://github.com/facebook/react/blob/main/packages/react/src/ReactHooks.js) (lines 73-79), the `useReducer` hook resolves a dispatcher from `ReactSharedInternals.H` and returns a `dispatch` function bound to that specific component's fiber queue. This `dispatch` triggers React's internal scheduling mechanism to re-render the component with updated state.

```javascript
// Conceptual implementation from React source
function useReducer(reducer, initialState) {
  const dispatcher = resolveDispatcher(); // From ReactSharedInternals.H
  return dispatcher.useReducer(reducer, initialState);
  // Returns [state, dispatch] where dispatch updates fiber state
}

```

### useDispatch in React Redux

Conversely, `useDispatch` in [`reduxjs/react-redux/src/hooks/useDispatch.ts`](https://github.com/facebook/react/blob/main/reduxjs/react-redux/src/hooks/useDispatch.ts) accesses the Redux store via React's context API (`ReactReduxContext`) and returns the store's native `dispatch` method. This creates a bridge between React's component tree and Redux's external state container.

```typescript
// From react-redux source (simplified)
function useDispatch() {
  const store = useContext(ReactReduxContext).store;
  return store.dispatch; // Direct reference to Redux store dispatch
}

```

## Code Examples

### Local State with useReducer

Use the traditional `dispatch` function when state is isolated to a single component or subtree. In `facebook/react`, this pattern leverages the fiber architecture for efficient updates.

```tsx
import React, { useReducer } from 'react';

type State = { count: number };
type Action = { type: 'increment' } | { type: 'decrement' };

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      return state;
  }
}

export function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

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

```

### Global State with useDispatch

Use the `useDispatch` hook when interacting with Redux's global store, enabling middleware pipelines and cross-component state sharing.

```tsx
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './counterSlice';

export function Counter() {
  const count = useSelector(state => state.counter.value);
  const dispatch = useDispatch();

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => dispatch(increment())}>+</button>
      <button onClick={() => dispatch(decrement())}>-</button>
    </div>
  );
}

```

### When to Use Each Approach

**Choose `useReducer` (traditional dispatch) for:**
- Component-specific UI state (toggles, forms, counters)
- Complex state logic that would be messy with `useState`
- State that doesn't need to persist across route changes or share with distant components

**Choose `useDispatch` (React Redux) for:**
- Application-wide data (user authentication, API caching, theme settings)
- State requiring middleware (logging, thunks, sagas for async operations)
- Complex cross-cutting concerns where multiple components read and write the same data

```tsx
// useReducer – simple UI toggle
function Toggle() {
  const [on, toggle] = useReducer(prev => !prev, false);
  return <button onClick={toggle}>{on ? 'ON' : 'OFF'}</button>;
}

// useDispatch – global async action
function SaveProfileButton({ profile }) {
  const dispatch = useDispatch();
  return (
    <button onClick={() => dispatch(updateProfileAsync(profile))}>
      Save
    </button>
  );
}

```

## Summary

- **Traditional `dispatch`** from `useReducer` manages **component-local state** through React's fiber architecture, as implemented in [`packages/react/src/ReactHooks.js`](https://github.com/facebook/react/blob/main/packages/react/src/ReactHooks.js).
- **`useDispatch`** from React Redux provides access to a **global Redux store**, enabling middleware support and cross-component state sharing via [`src/hooks/useDispatch.ts`](https://github.com/facebook/react/blob/main/src/hooks/useDispatch.ts).
- Use `useReducer` for isolated UI logic and `useDispatch` for application-wide state requiring persistence, middleware, or complex async workflows.

## Frequently Asked Questions

### Can I use useDispatch without Redux?

No, the `useDispatch` hook specifically requires a Redux store provided by the `Provider` component from `react-redux`. Without Redux, you should use React's built-in `useReducer` for state management or `useState` for simpler cases.

### Does useDispatch trigger re-renders differently than useReducer?

Yes. When you call `dispatch` from `useReducer`, React schedules an immediate update to that component's fiber state. With `useDispatch`, the action flows to the Redux store first; React components only re-render when `useSelector` or `connect` detects a change in the selected state slice, not directly from the dispatch call itself.

### Which should I choose for form state management?

For simple, self-contained forms, `useReducer` provides sufficient state management without adding Redux complexity. For multi-step forms that persist data across routes, require validation middleware, or share progress with other components, `useDispatch` with Redux offers better architectural support.

### How do I test components using useDispatch?

Tests for components using `useDispatch` typically wrap the component in a `Provider` with a mock or test-specific Redux store. Alternatively, you can mock the `react-redux` module to return a controlled dispatch function. This differs from testing `useReducer` components, where you simply interact with the rendered component and assert on state changes directly.