React Easy technical 0 views 2 min read

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

Peer-reviewed by HireXTech Technical Panel Updated for 2025/2026 hiring Editorial standards
Practise this track
Interviewer Expectations for this Question
01
Core Competency

Assesses fundamental understanding of React conventions, runtime behavior, and memory/performance considerations.

02
Evaluation Criteria

Hiring managers look for precision, avoidance of ambiguous jargon, and ability to explain trade-offs under real production conditions.

Comprehensive Model Answer Verified Solution

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 (
         <div>
           <p>Count: {state.count}</p>
           <button onClick={handleClick}>Increment Twice</button>
         </div>
       );
     }
     

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.

Candidate Response Strategy & Interview Tips

  1. Start with a concise one-sentence summary: Deliver a direct, confident answer first before expanding into nuances.
  2. Demonstrate real-world trade-offs: Discuss where this approach excels and when you would avoid it in production systems.
  3. Discuss complexity & edge cases: Proactively explain time/space complexity or boundary conditions (null values, scale limits).
  4. Prepare for interviewer follow-ups: Technical hiring panels frequently probe deeper into concurrency, backward compatibility, or alternative libraries.
Related Topics & Skills
Spotted an error or have an alternative solution?