This episode breaks down Redux's three principles: single source of truth, read-only state, and pure reducers. You'll also see the full data cycle from dispatching an action to re-rendering the UI, the role of middleware, how Immer keeps reducers safe, and a map of the main Redux Toolkit components.

In episode 1 you learned why Redux was born. Now we go one level deeper: how Redux works and what its building blocks are. Episode 2 is the bridge between concepts and code — after this, all the hands-on episodes will make more sense because you'll already understand the foundation.
We'll cover Redux's three principles, the complete data cycle from dispatch to UI re-render, the role of middleware and Immer, and a map of the main Redux Toolkit components. Think of this episode as an architectural map: every following episode simply fills in one room of that map at a time.
All application state is stored in one store shaped as a single JavaScript object tree. Any component can read the state, but only the store holds true ownership.
const state = store.getState()store.getState() always returns the latest state snapshot. Because there's only one store, there are no two data sources that could contradict each other — this is what makes debugging and auditing easy.
State cannot be changed directly from the outside. The only way to change state is by dispatching an action — a descriptive object that states what happened.
const action = { type: "todos/toggle", payload: "todo-1" }
store.dispatch(action)The action { type: "todos/toggle", payload: "todo-1" } only describes the intent; it doesn't make the change itself. store.dispatch(action) hands the action to the reducer for processing. This constraint keeps the state change flow centralized and traceable.
A reducer is a pure function that receives state and action, then returns new state. Pure means: same input, same output; it never reads global data; and it never performs side effects.
function counterReducer(state = { count: 0 }, action) {
if (action.type === "counter/increment") {
return { count: state.count + 1 }
}
return state
}counterReducer(state, action) doesn't modify the old state; instead it returns a new object { count: state.count + 1 }. Because it's pure, a reducer is easy to test and its results are always deterministic.
While the application runs, this cycle repeats continuously:
dispatch(action) -> reducer -> store (new state) -> notify subscriber -> UI re-renderdispatch(action).Note: store.subscribe(fn) is a low-level API you usually won't touch directly — react-redux connects it through hooks like useSelector.
Middleware sits between dispatch and the reducer. It can observe actions, modify them, stop them, or run side effects. The most popular examples are Redux Thunk for async functions and createListenerMiddleware for centralized reactions.
dispatch(action) -> [middleware...] -> reducer -> storeWithout middleware, dispatch only accepts action objects. With thunk, dispatch can also accept functions containing async logic — this is the foundation of createAsyncThunk, which we'll learn in episode 6.
Writing immutable updates by hand is error-prone. Redux Toolkit injects Immer into reducers, so you can write code that looks like direct mutation:
const slice = createSlice({
name: "counter",
initialState: { count: 0 },
reducers: {
increment(state) {
state.count += 1
},
},
})state.count += 1 looks like mutation, but Immer creates a temporary draft and produces a new state object behind the scenes. We'll explore Immer's draft and frozen state mechanics more deeply in episode 19.
To make navigation easier for the rest of the series, here's a map of the main RTK components:
configureStore: creates a store with default middleware and DevTools.createSlice: writes a reducer + action creators in one block.createAsyncThunk: async actions with pending, fulfilled, rejected lifecycle.createEntityAdapter: manages collections of normalized entities.createListenerMiddleware: reactive, action-based middleware.createApi for fetching and caching server data.Each of these will be covered specifically in episodes 3 through 22. For now, just memorize their names and roles.
Episode 2 gives you the lens to read the rest of the series: Redux's three principles, unidirectional data flow, middleware as the home of side effects, Immer as the reducer safety net, and the RTK component map.
Key takeaways:
In the next episode, episode 3, you'll start practicing: store setup and Provider — creating your first store with configureStore, wrapping the app with Provider from react-redux, and laying out the app and features folder structure we'll use throughout this series.