13) useReducer Hook
Concept of useReducer
TheuseReducerhook in React is a state management hook used when your component’s state logic becomes complex — especially when the state transitions depend on actions, or when multiple pieces of state update together.
It works similar to a Redux-like reducer pattern: You have state, You have actions and A reducer function decides how the state changes based on the action.const [state, dispatch] = useReducer(reducer, initialState);Parameters -
i) reducer - A function(state, action) => newState
ii) initialState - The starting state value
Return Values -
iii) state - The current state
iv) dispatch - A function used to send actions to the reducerExample of useReducer
import React, { useReducer } from 'react'; const initialState = { count: 0 }; const reducer = (state, action) => { switch (action.type) { case 'increment': return { count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; default: return state; } }; const getIncrementValue = () => { dispatch({ type: "increment" }); } const getDecrementValue = () => { dispatch({ type: "decrement" }); } function Counter() { const [state, dispatch] = useReducer(reducer, initialState); return ( <div> <p>Count: {state.count}</p> <button onClick={getIncrementValue}>Increment</button> <button onClick={getDecrementValue}>Decrement</button> </div> ); } export default Counter;When to Use useReducer
i) State logic is complex
Multiple sub-values and Next state depends on previous state
ii) Multiple state updates must be grouped
(e.g., forms, complex UI components)
iii) State transitions follow a clear pattern
e.g., loading → success → error
iv) You want predictable, testable state updates
v) You're lifting state or managing global-like state without adding Redux
vi) When managing form submission.How useReducer Works
i) You define a reducer
A reducer is a pure function that receives the current state and the action
And returns the next stateconst reducer = (state, action) => { switch (action.type) { case "increment": return { count: state.count + 1 }; case "decrement": return { count: state.count - 1 }; default: return state; } }ii) You initialize the state with useReducer
React calls your reducer internally and gives you:state→ the current statedispatch→ a function for triggering actionsconst [state, dispatch] = useReducer(reducer, { count: 0 });iii) You trigger changes using dispatch
When something happens (button click, input change, etc.),dispatch({ type: "increment" });iv) React calls the reducer and updates the UI
After you dispatch an action,
React calls your reducer(state, action) internally.
Reducer returns a new updated state.
React re-renders the component with that new state.
This keeps state updates predictable & structured.Basic Interview Questions
i) What is the useReducer hook in React?
ii) How does useReducer differ from useState?
iii) What is the syntax of the useReducer hook?
iv) What are the parameters of useReducer?
v) What does dispatch do in useReducer?
vi) What is a reducer function?
vii) What is the purpose of the action object in useReducer?
viii) What does useReducer return?
ix) When should you use useReducer over useState?
x) Can you update multiple state values using one action in useReducer?Intermediate Interview Questions
i) How does the reducer function maintain purity?
ii) What happens if the reducer returns the same state?
iii) How do you handle complex state updates using useReducer?
iv) Can useReducer be used with useContext? How?
v) How do you pass arguments to the dispatch function?
vi) What is lazy initialization in useReducer?
vii) How do you optimize performance in components using useReducer?
viii) Can you explain the concept of action types and payloads?
ix) Can you compare Redux reducers and React’s useReducer reducers?
x) How do you structure reducers for readability?Advanced / Scenario-Based Questions
i) When is useReducer NOT a good choice?
ii) How do you split a large reducer into smaller reducers (like combineReducers)?
iii) How do you handle asynchronous logic with useReducer?
iv) How do you test a reducer function?
v) How do you memoize a dispatch function or avoid unnecessary re-renders?vi) Can you implement a form state using useReducer?
vii) What patterns do you follow to avoid deeply nested state updates?
viii) How do you debug complex reducer-driven components?
ix) How does React ensure the reducer is stable across renders?
x) How would you manage side effects with useReducer? (e.g., using middleware-like patterns or hooks)Hands-On / Coding Interview Questions
i) Implement a counter using useReducer.
ii) Implement a todo list using useReducer.
iii) Build a form with multiple fields using useReducer.
iv) Show how to handle loading, success, and error states with useReducer.
v) Refactor a component using many useState calls into one useReducer.
vi) Write a reducer that updates nested properties safely.
vii) Write an example using lazy initialization with useReducer.Tricky/Conceptual Questions
i) Why must reducer functions be pure?
ii) What happens if you mutate the state object inside the reducer?
iii) Why should you never perform side effects inside the reducer?
iv) Why is dispatch reference stable across renders?
v) Can dispatch cause batching of updates? How?
vi) How does React decide when to re-render components using useReducer?vii) Why shouldn’t reducers depend on props or external variables?
viii) Can you share one reducer across multiple components?
ix) What’s the difference between dispatching an action and calling a setter?
x) How do you prevent reducer inflation (too many action types)?