Understanding useReducer in React
React provides several hooks to manage state in function components. Among these, useReducer stands out as a powerful alternative to useState, especially for managing complex state transitions. In this guide, we will break down how to master the useReducer hook, share best practices, and walk through 10 practical examples to help you build better React applications.
Let’s dive deep into usereducer, understand its use cases, and learn when it’s better than other hooks.
How useReducer Works in React
The useReducer hook is based on the concept of a reducer function, familiar to those who have worked with Redux. It is a pure function that takes in the current state and an action, and returns a new updated state.
Unlike useState, which simply updates a value, useReducer is best suited when:
State logic is complex.
The next state depends on the previous state.
There are multiple related state values.
Basic useReducer Syntax Explained
Here’s the basic syntax of usereducer in react:
reducer: A function that determines how the state should change.
initialState: The initial value of the state.
state: The current state.
dispatch: A function to trigger state changes.
Example of a simple reducer:
state: The current state object (example:{ count: 5 }).action: An object that usually has at least atypeproperty (example:{ type: 'increment' }).switch (action.type): Checks what kind of action you want to perform.return: Always returns a new state object (important for keeping things immutable — not directly changing the old state).
Why Choose useReducer Over useState?
Better state organization: Manage complex logic cleanly.
Predictable updates: Actions define explicit state transitions.
Easier debugging: Centralized reducer functions.
Scalable code: Especially useful when the app grows.
10 Practical Examples of useReducer in React
Let’s now see 10 detailed examples of usereducer hook usage.
1. Basic Counter Example
useReducer import:
→ Brings inuseReducerfrom React to manage complex state.initialState:
→ Sets the starting state{ count: 0 }.reducer function:
→ Takes currentstateandaction, and returns the new updated state.Counter component:
→ UsesuseReducerto getstateanddispatchfunction.dispatch:
→ Sends actions (incrementordecrement) to the reducer.UI (JSX):
→ Shows the current count and provides buttons to update it.
2. Managing Form State
initialState:
→ Starts with emptynameandemailfields.reducer function:
→ Updates the specific field (nameoremail) without changing the rest of the state.Form component:
→ UsesuseReducerto manage form data.handleChange function:
→ Dispatches the input’snameandvalueto update the correct field.Inputs (UI):
→onChangecallshandleChange, and inputs show the lateststatevalues.Output:
→ Displays the fullstateas a JSON string below the inputs.
3. Toggle Theme (Light/Dark Mode)
initialState:
→ Starts with the theme set to'light'.reducer function:
→ Switches the theme between'light'and'dark'when thetoggleaction is dispatched.ThemeToggle component:
→ UsesuseReducerto manage theme state and update it based on button clicks.dispatch with
toggleaction:
→ When the button is clicked, thedispatchsends the action{ type: 'toggle' }to the reducer.state.themein className:
→ Applies the current theme ('light'or'dark') to thediv‘s class name to dynamically change the theme style.
4. Managing Multiple Inputs
initialState:
→ Initializesusernameandpasswordas empty strings.reducer function:
→ Updates the corresponding field (usernameorpassword) in the state based on thenameandvalueof the input field.LoginForm component:
→ UsesuseReducerto manage form state and updates theusernameandpasswordbased on user input.dispatch with
e.target:
→ When a user types into either theusernameorpasswordinput, thedispatchfunction is called, passinge.target(which containsnameandvalueproperties) to the reducer.Inputs (UI):
→ Thevalueof each input is tied to the corresponding state field (state.usernameorstate.password), ensuring the inputs are controlled components.
5. Cart Management in E-commerce
initialState:
→ Starts with an empty array[]representing the cart.reducer function:
→ Handles two actions:add: Adds a product to the cart.remove: Removes a product from the cart by filtering out the item with the givenid.
Cart component:
→ UsesuseReducerto manage thecartstate, allowing items to be added and removed.dispatchwithaddaction:
→ When the “Add Product” button is clicked, an item is added to the cart with theidandnameproperties.dispatchwithremoveaction:
→ Each item in the cart has a “Remove” button that removes the item by dispatching theremoveaction with the item’sid.Rendering the Cart:
→ The cart is rendered as a list of products. Each product has its name displayed along with a “Remove” button.
6. Step Wizard Form
initialState:
→ Initializes withstep: 1, indicating the starting step in the wizard.reducer function:
→ Handles two actions:next: Increases the current step by 1.previous: Decreases the current step by 1.
Wizard component:
→ UsesuseReducerto manage the current step, and renders the current step and buttons to navigate between them.dispatchwithnextaction:
→ When the “Next” button is clicked, thestepis incremented by 1.dispatchwithpreviousaction:
→ When the “Back” button is clicked, thestepis decremented by 1.Displaying the current step:
→ The current step is displayed in the<p>element.
7. Show/Hide Password
initialState:
→ Initializes withshowPassword: false, meaning the password is initially hidden.reducer function:
→ Handles the action to toggle the visibility of the password:toggle: Flips theshowPasswordstate betweentrue(show) andfalse(hide).
PasswordToggle component:
→ UsesuseReducerto control the visibility of the password input field.dispatchwithtoggleaction:
→ Clicking the “Show/Hide” button dispatches thetoggleaction to change theshowPasswordstate.Password input type change:
→ The input field type switches betweentext(show password) andpassword(hide password) based onstate.showPassword.
8. Notification Handler
initialState:
→ Initializes withmessage: ''andtype: ''to store the message and its associated type.reducer function:
→ Updates the state with the newmessageandtypevalues based on the dispatched action.Notifications component:
→ UsesuseReducerto handle the state and display notifications with different types.dispatchwithsuccessaction:
→ Clicking the “Success” button triggers thedispatchto set the message to'Success!'and type to'success'.dispatchwitherroraction:
→ Clicking the “Error” button triggers thedispatchto set the message to'Error occurred'and type to'error'.Notification display:
→ The message is displayed conditionally, and the notification type is applied dynamically to set the appropriate style (e.g.,alert-successoralert-error).
9. Loading State Management
initialState:
→ Initializes withloading: false, meaning the process is not currently loading.reducer function:
→ Handles two actions:start: Setsloadingtotrue, indicating the loading process has started.end: Setsloadingtofalse, indicating the loading process has finished.
Loader component:
→ UsesuseReducerto track whether the system is loading or done and displays the appropriate message.dispatchwithstartaction:
→ Clicking the “Load” button triggers thedispatchwith{ type: 'start' }to setloadingtotrue.dispatchwithendaction:
→ Clicking the “Finish” button triggers thedispatchwith{ type: 'end' }to setloadingtofalse.Conditional rendering:
→ The component displays either “Loading…” or “Done!” based on the value ofstate.loading.
10. Complex Calculator
initialState:
→ Initializes withtotal: 0, starting the calculator with a total value of zero.reducer function:
→ Handles three actions:add: Increases thetotalby the value provided in the action.subtract: Decreases thetotalby the value provided in the action.reset: Resets thetotalback to0.
Calculator component:
→ UsesuseReducerto manage and update thetotalvalue.dispatchwithaddaction:
→ Clicking the “Add 5” button triggers thedispatchwith{ type: 'add', value: 5 }, adding 5 to the current total.dispatchwithsubtractaction:
→ Clicking the “Subtract 3” button triggers thedispatchwith{ type: 'subtract', value: 3 }, subtracting 3 from the current total.dispatchwithresetaction:
→ Clicking the “Reset” button triggers thedispatchwith{ type: 'reset' }, setting the total back to 0.Display the total:
→ The total is displayed dynamically, updating each time the state changes based on user input.
Best Practices for useReducer in React
Always keep reducer functions pure.
Use constants for action types to avoid typos.
Modularize reducer logic in large applications.
Handle default cases in reducers.
Avoid unnecessary re-renders by using React.memo if needed.
Frequently Asked Questions (FAQs)
What is useReducer in React?
- useReducer is a React Hook that lets you manage complex state logic in a function component through a reducer function, providing an alternative to useState.
When should I use useReducer?
- Use useReducer when state logic involves multiple sub-values, complex conditions, or depends on previous state transitions.
What’s the difference between useState and useReducer?
useState is simpler for single values.
useReducer is better for complex or related state changes that require multiple actions.
Can I replace Redux with useReducer?
- In small applications, yes. useReducer manages local component state similarly to Redux but without the full global state management overhead.
How do I structure actions in useReducer?
- Use type and optional payload inside action objects to clearly define what change should happen in your reducer.
Final Thoughts
Mastering the usereducer hook is a crucial skill for modern React developers. With a good grasp of useReducer in React, you can manage complex component states much more effectively, making your code scalable, maintainable, and professional.
Keep practicing these examples, and soon using usereducer will feel natural in your React development journey!


This is a simple example of a reducer function in JavaScript. It demonstrates how to handle state changes in a predictable way. The reducer takes the current state and an action as arguments, then returns a new state based on the action type. It’s a fundamental concept in state management libraries like Redux. Why is using a reducer considered beneficial for managing application state?