Redux
Predictable state container with a strict unidirectional data flow and time-travel debugging.
What it is
Redux is a predictable state container for JavaScript apps. It helps manage application state in a single store, enabling easier debugging, testing, and predictable behavior across the app.
Redux uses a single store to hold the entire state of the application. State changes are made via actions and handled by pure reducer functions. Middleware can extend Redux with additional capabilities like async actions.
- Watch for
- Use Redux Toolkit, not hand-written reducers — the old boilerplate is why Redux got its reputation
- Licence
- MIT
When to use it
The question documentation cannot answer for you — because it cannot recommend something else.
Reach for it when
- Large applications where many distant components share and mutate the same state
- You need the DevTools' action log and time-travel debugging to understand what happened
- A team that benefits from one enforced, explicit pattern for every state change
Look elsewhere when
- Most of your 'state' is really server data — React Query or SWR handles that far better
- The application is small; Zustand or plain context is a fraction of the code
Installation
npm install reduxGetting started
The smallest useful thing you can do with it, and what each part means.
import { createStore } from 'redux';
const initialState = { count: 0 };
const reducer = (state = initialState, action) => {
switch(action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
default:
return state;
}
};
const store = createStore(reducer);
console.log(store.getState());store.dispatch({ type: 'INCREMENT' });
console.log(store.getState());Advanced usage
Where the library earns its place over a simpler alternative.
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
const asyncAction = () => dispatch => {
setTimeout(() => {
dispatch({ type: 'INCREMENT' });
}, 1000);
};
const store = createStore(reducer, applyMiddleware(thunk));
store.dispatch(asyncAction());import { combineReducers, createStore } from 'redux';
const reducerA = (state = 0, action) => action.type === 'A' ? state + 1 : state;
const reducerB = (state = 0, action) => action.type === 'B' ? state + 1 : state;
const rootReducer = combineReducers({ a: reducerA, b: reducerB });
const store = createStore(rootReducer);store.subscribe(() => console.log('State updated:', store.getState()));
store.dispatch({ type: 'INCREMENT' });Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- State not updating as expected
- Ensure that reducers return a new state object instead of mutating the existing state.
- Middleware not working
- Check that middleware is applied correctly using `applyMiddleware` when creating the store.
- Dispatching unknown action types
- Ensure the action type matches what your reducer is handling.
Best practices
- Keep state normalized and avoid nested structures when possible.
- Use action creators to encapsulate action creation logic.
- Keep reducers pure and free of side effects.
- Use middleware for async actions instead of placing side effects in reducers.
- Use Redux DevTools for debugging and inspecting state changes.
Alternatives
Comparable options, and the reason you would pick one over the other.
Background
Why it exists, and what it was reacting to.
Redux was created by Dan Abramov and Andrew Clark in 2015. It was inspired by Flux but simplified the architecture, emphasizing a single immutable state tree and pure reducers. Redux became widely adopted for complex React applications to manage state consistently.
