If you’ve worked with React long enough, you’ve probably seen two things with “reducer” in the name:
- The
useReducerhook in React - Reducers in Redux
They sound similar… and they kind of are — but they live in different neighbourhoods.
Let’s break it down.
🎯 The Core Idea: What’s a Reducer?
Both useReducer and Redux reducers are built on the same concept:
A reducer is just a function that:
- Takes the current state and an action
- Returns the next state
In plain JavaScript, it looks like this:
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
}
No side effects. No mutations. Just a pure function.
🪝 useReducer in React
useReducer is a React hook for managing state in a single component (or a small group of components via props or context).
Example:
import React, { useReducer } from 'react';
function Counter() {
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
}
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</>
);
}
Key points about useReducer:
- State is local to the component (unless you manually share it via context)
- No middleware, no dev tools, no global store
- Great for complex local state updates
🏪 Redux Reducers
In Redux, a reducer works the same way — but instead of local state, it updates a global store that can be accessed anywhere in your app.
Example:
// reducer.js
function counterReducer(state = { count: 0 }, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
}
export default counterReducer;
// store.js
import { createStore } from 'redux';
import counterReducer from './reducer';
const store = createStore(counterReducer);
// Component.jsx
import { useSelector, useDispatch } from 'react-redux';
function Counter() {
const count = useSelector(state => state.count);
const dispatch = useDispatch();
return (
<>
<p>Count: {count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</>
);
}
Key points about Redux reducers:
- State is global
- Supports powerful middleware (like Redux Thunk, Redux Saga)
- Integrated with dev tools for debugging
- Usually used in large, complex apps
🔍 How They’re the Same
Both are built on the same reducer concept from functional programming.
🔀 How They’re Different
💡 Which Should You Use?
Use useReducer when:
- The state is complex, but only relevant to one component or a small subtree.
- You don’t need global state sharing.
- You want to avoid pulling in Redux for something small.
Use Redux reducers when:
- You need global state management.
- You want advanced debugging, time travel, and middleware.
- Your app is big enough to justify the extra setup.
🏁 Final Takeaway
useReducer and Redux reducers are like bicycles and buses — they both get you from state A to state B, but one is for short, personal trips (local component state), and the other is for carrying the whole city (global app state).
They share the same functional programming DNA, but live in different ecosystems.
Thank you for reading! Feel free to connect with me on LinkedIn or GitHub.


Top comments (0)