Redux
Redux
Redux is a predictable state container for JavaScript apps. For many years, it was the absolute standard for managing global state in React applications.
Redux is based on the Flux architecture (originally proposed by Facebook) and enforces a strict, unidirectional data flow.
The Core Principles of Redux
Redux operates on three fundamental principles:
- Single Source of Truth: The entire state of your application is stored in an object tree within a single Store.
- State is Read-Only: The only way to change the state is to emit an Action (an object describing what happened). You cannot mutate the state directly.
- Changes are made with Pure Functions: To specify how the state tree is transformed by actions, you write pure functions called Reducers.
The Redux Flow
- The Store: Holds the global state object.
const state = store.getState(). - The View (React Component): Reads data from the store and displays it.
- The Action: When a user interacts with the view (e.g., clicks “Add to Cart”), the view dispatches an action. An action is just a plain JavaScript object with a
typeproperty.const action = { type: 'ADD_TO_CART', payload: { id: 1, name: 'Apple' } }; dispatch(action); - The Reducer: The Store sends the current state and the dispatched action to the Reducer. The Reducer uses a
switchstatement (usually) to look at the actiontype, and returns a brand new state object with the updates applied.function cartReducer(state = [], action) { switch (action.type) { case 'ADD_TO_CART': // NEVER mutate state directly (e.g., state.push()). // Always return a new copy. return [...state, action.payload]; default: return state; } } - Update: The Store saves the new state. The React components that are subscribed to the store re-render with the new data.
React-Redux
Redux itself is completely UI-agnostic. To use it with React, you use the react-redux binding library.
It provides a <Provider> component to wrap your app (passing the store down via Context), and hooks like useSelector (to read data) and useDispatch (to send actions).
import { useSelector, useDispatch } from 'react-redux';
function CartBadge() {
// Read from the store
const itemCount = useSelector(state => state.cart.length);
return <span>{itemCount} Items</span>;
}
function Product({ item }) {
const dispatch = useDispatch();
// Dispatch an action to the store
return (
<button onClick={() => dispatch({ type: 'ADD_TO_CART', payload: item })}>
Add to Cart
</button>
);
}
Why use Redux?
- Predictability: Because state is read-only and reducers are pure functions, bugs are very easy to track down. Given a specific state and a specific action, the resulting state is always identical.
- DevTools: The Redux DevTools extension is incredibly powerful. It allows you to “time-travel” (rewind and replay actions) and see exactly how your state mutated over time.
- Ecosystem: There is a massive ecosystem of middleware (like Redux Thunk or Redux Saga for handling asynchronous logic).
The Decline of “Vanilla” Redux
While the concepts of Redux are brilliant, “Vanilla” Redux requires an immense amount of boilerplate code. For a simple feature, you have to create Action Types, Action Creators, and write complex, immutable Reducer logic.
Because of this, modern React development has largely moved away from Vanilla Redux in favor of Redux Toolkit (RTK) or lighter alternatives like Zustand.
Interview Questions
Q: What are the three core principles of Redux?
A:
- Single Source of Truth: The entire state of your application is stored in an object tree within a single store.
- State is Read-Only: The only way to change the state is to emit an action (an object describing what happened).
- Changes are made with Pure Functions: To specify how the state tree is transformed by actions, you write pure reducers that return completely new state objects rather than mutating the old ones.