How Redux Moves Data: The One-Way Cycle
Redux enforces a strict one-way data flow. Here's how an action travels through dispatch, store, and reducer before anything in your app changes.
In regular React, a button click can update state in the owning component directly. The state lives wherever you wired it up. A bug means checking every possible place that touches that state.
In Redux, a button click can only do one thing: create an action.
That single constraint, forcing all state changes through a fixed sequence, is what makes Redux state predictable.
When something breaks in production, you do not ask "which component mutated this." You ask "which action caused this." The answer is always one step away.
The Five Stages
Redux data moves through five stages, in order, every single time a state change happens:
ExpandThe Redux data flow cycle
Nothing bypasses this path. No shortcuts, no direct mutations.
Stage 1: The Action
An action is a plain JavaScript object. It describes what happened. Nothing more, nothing less.
{ type: 'TOGGLE_THEME' }
{ type: 'ADD_TO_CART', payload: { id: 42, name: 'Wireless Headphones' } }The type field is required. It is the name of the operation that happened. The payload field is optional. It carries any data the operation needs.
An action cannot update state. It has no authority to act. It is a description of intent, not an execution.
That distinction matters when debugging. Every action dispatched in a Redux app is logged. You can read the history: "at this point in time, this specific thing happened, with this specific data." That log becomes your audit trail.
Stage 2: dispatch()
dispatch() is the single function that sends an action into the Redux system.
dispatch({ type: 'TOGGLE_THEME' })Your component calls dispatch and its job ends there. It does not know what happens to that action afterward.
dispatch is the only way to trigger a state change. There is no backdoor. That restriction is the enforcement mechanism for the entire one-way flow.
Stage 3: The Store
The store receives the action from dispatch and forwards it to every reducer in the application, one by one, in sequence.
The store does not decide what to do with the action. It has no logic of its own. It receives, routes, and stores. The actual computation happens in the reducer.
Stage 4: The Reducer
This is where the logic lives.
function themeReducer(state = { isDark: false }, action) {
if (action.type === 'TOGGLE_THEME') {
return { isDark: !state.isDark }
}
return state
}A reducer receives the current state and the action. It returns the new state. That is the entire contract.
Two rules make a function a "reducer" in the Redux sense:
- It never modifies state directly. It creates and returns a new object. The original state stays unchanged.
- It always returns something. If the action type does not match anything it knows about, it returns the current state unchanged.
A reducer is a pure function: same inputs always produce the same output, no side effects, no network calls.
That purity is what makes time-travel debugging possible. Because the reducer is deterministic, you can replay any sequence of actions and arrive at exactly the same state. Redux DevTools works because pure functions are reproducible.
Stage 5: New State, Component Re-renders
The value the reducer returns becomes the new state in the store. The store notifies every subscribed component. Those components re-render with the updated values.
The cycle is complete. The next user interaction starts a fresh cycle through all five stages.
Why the Constraint Exists
Every bug in a stateful application starts with two questions.
What is the current state? What caused it to get there?
In regular React, the answer to "what caused it" can be any of the places that call setState. In Redux, the answer is always "one of the actions in this log, dispatched in this order."
That is the entire point of one-way flow. Not performance. Not conciseness.
Traceability.
In the previous post, Redux was about eliminating prop drilling. That is the what. This cycle is the how: the mechanical guarantee that makes debugging tractable at scale.
Next: building this in actual code. A quiz score tracker with a reducer, a store, dispatch, and getState. Every piece working together.
The Essentials
- An action is a plain object with a
typefield. It describes what happened but cannot change state on its own. dispatch(action)is the only entry point for triggering state changes. There is no other way into the Redux state.- The reducer is a pure function that takes
(state, action)and returns new state. It never mutates state directly. Same inputs always produce the same output.
Further Reading and Watching
- Redux Core Concepts: the official primer on actions, reducers, and the store
- Redux Fundamentals, Part 2: Concepts and Data Flow: deeper walkthrough of the full cycle from the official docs
Practice what you just read.
Keep reading