Understand Redux in one page
This page is the quick-reference version of your project. It explains what each part means, how action names are generated, how data flows, and how persistence works in this codebase.
Memory line: Click -> Dispatch -> Reducer -> Store -> UI
Short code: C D R S U
Core Concepts
Store
One global state tree.
state.counter.value, state.todos.items, state.user.name
Slice
One feature bundle: state + reducers + actions.
counterSlice, todosSlice, cartSlice
Action
Plain object that describes what happened.
{ type: 'counter/increment' }
Payload
Extra data in an action.
{ type: 'todos/addTodo', payload: 'Read docs' }
Reducer
Function that updates state from action.
increment, addTodo, setQuantity
Dispatch
Sends action into Redux pipeline.
dispatch(addTodo(text))
Selector
Reads a specific value from store.
useAppSelector((s) => s.todos.items)
Middleware
Runs between dispatch and reducer.
flowLoggerMiddleware, thunk middleware
Async thunk
Handles async, dispatches lifecycle actions.
async/fetchUser/pending -> fulfilled|rejected
Persistence
Save and restore state across refresh.
localStorage key: redux-flow-state-v1
Action Name Generation
For createSlice: action.type = sliceName/reducerName
Redux Pipeline (What Happens)
- 1. User interaction triggers a component handler.
- 2. Component calls dispatch(actionCreator(payload)).
- 3. Middleware runs (thunk/default + flow logger).
- 4. Reducer with matching type updates its slice.
- 5. Store now has new state.
- 6. Selectors detect changed selected values.
- 7. Only affected components re-render.
Thunk (Async Made Easy)
What is a thunk?
A thunk is an async action function. Instead of returning a plain action object immediately, it runs async work (API call, timer, etc.) and dispatches lifecycle actions for you.
pending -> fulfilled | rejected
Project example
Persistence (Save Across Refresh)
How it works in this project
- 1. Store subscribes to changes and saves to localStorage.
- 2. Key used: redux-flow-state-v1.
- 3. Provider reads saved state after mount (useEffect).
- 4. Provider dispatches loadSnapshot to rehydrate state.
- 5. Delete data button opens modal, clears storage, resets Redux.
Why this avoids hydration errors
The first server render and first client render both start with the same default state. Persisted data is applied only after mount, so server/client HTML matches during hydration.
Use This Daily
When stuck, ask in this order:
- 1. Which action was dispatched?
- 2. Which reducer should handle this type?
- 3. Did state actually change?
- 4. Is selector reading the correct field?
- 5. Is data persisted or reset intentionally?