createAsyncThunk and a logging middleware
The thunk itself never reaches the reducers; the middleware only logs the plain actions it dispatches. await dispatch(thunk) resolves with the final action (it doesn't throw on failure; call .unwrap() on the result if you want a thrown error).
Redux keeps app state in one store that changes only when you dispatch an action, which a pure reducer turns into the next state; Redux Toolkit is the official, modern way to write it, with slices, Immer, thunks, memoised selectors and RTK Query.
Change the code and press Run (Ctrl+Enter). Predict what will happen first, then break it on purpose and read what changes. Your edits are saved and match the lesson page.
Ready for more? This phase has 5 hands-on exercises with automatic checks.
Practice questions
Write the code in the editor, run it, then open the model answer to compare.
Write a counterSlice with incremented, decremented and incrementedBy(amount), configure a store, and dispatch three actions from plain JavaScript, logging the state each time.
Write a memoised selector selectTotal that returns the cart total from state.cart.items (each item has price and qty).
Explain it without notes
Explain Redux's data flow from a click to a re-render.
What does Redux Toolkit add over plain Redux, and why can slice reducers "mutate"?
How does useSelector decide whether to re-render, and why do you need memoised selectors?
What does createAsyncThunk do, and when would you use RTK Query instead?
When is Redux a good fit, and when is it overkill?
Preview
Console
Nothing logged yet.Expected console output
render Profile: idle
action: user/fetch/pending
render Profile: loading
action: user/fetch/fulfilled
render Profile: succeeded
action: user/fetch/pending
render Profile: loading
action: user/fetch/rejected
render Profile: failed
thunk result type: user/fetch/rejected