FrontendDeveloper.in

React question detail

Is dispatch from useReducer asynchronous and does it update state immediately?

The dispatch function returned by useReducer is not asynchronous — it is a synchronous function call. When you call dispatch(action), React synchronously invokes your reducer with the current state and the action, computes the new state, and schedules a re-render. However, the state variable does not update immediately within the same render cycle. The updated state is only available in the next render.

This behavior is similar to useState's setState — React batches state updates for performance optimization, meaning the component does not re-render immediately after each dispatch call. Instead, React processes all dispatched actions and re-renders once with the final state.

Key Points

  1. dispatch is synchronous: The reducer runs immediately when dispatch is called.
  2. State update is not immediate in the current render: The state variable still holds the old value until the next render.
  3. React batches updates: Multiple dispatch calls within the same event handler result in a single re-render.
  4. Reducer is a pure function: It computes the new state without side effects.

Example demonstrating that state does not update immediately

import React, { useReducer } from 'react';

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

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

const handleClick = () => {
dispatch({ type: 'increment' });
console.log(state.count); // Still logs the OLD value (e.g., 0), not 1
dispatch({ type: 'increment' });
console.log(state.count); // Still logs the OLD value (e.g., 0), not 2
};

// After re-render, state.count will be 2 (both dispatches are processed)
return (
<button onClick={handleClick}>Increment Twice</button>
);
}

In the above example, even though dispatch is called twice, state.count still reflects the previous value inside the event handler. React batches both dispatches and re-renders the component once with count: 2.

How to read updated state after dispatch

If you need the updated value right after dispatching, you have several options:

  1. Use useEffect to react to state changes:
useEffect(() => {
console.log('Updated count:', state.count);
}, [state.count]);
  1. Compute the next state manually:
const handleClick = () => {
const nextState = reducer(state, { type: 'increment' });
console.log('Next state will be:', nextState.count);
dispatch({ type: 'increment' });
};
  1. Use useRef to track the latest state:
const stateRef = useRef(state);
useEffect(() => {
stateRef.current = state;
}, [state]);

Note: This behavior is by design in React. The dispatch function itself has a stable identity (it doesn't change between re-renders), which makes it safe to omit from useEffect dependency arrays.

Back to all React questions
Get LinkedIn Premium at Rs 399