← Back to Redux
Lesson 10 · State Management Fundamentals

Redux Terminology

Every Redux word you will meet in this course - store, action, reducer, dispatch, selector, middleware and more - defined once in simple English, shown working in one runnable script, with the pairs people mix up.

Beginner30 min

What you will be able to do

  • Define the core Redux terms in your own words
  • See each term in a running example and recognise it in real code
  • Tell apart the pairs people mix up: action and action creator, reducer and slice, selector and useSelector
  • Follow Redux naming conventions for actions, slices and selectors
  • Use this lesson as a reference for the rest of the course

The idea, in plain English

Lesson 9 showed the shape of Redux: the loop. This lesson gives every part of it a precise name. It ends Module 1, and it is written to be used later: when a word in Module 5 or Module 9 is not clear, come back here.

The terms are grouped by job: the data itself, describing changes, making changes, reading the state, and the helpers around the loop. Each definition is short and simple, with a line of code and a pointer to the module that teaches it properly.

All the terms are also shown working in one script, glossary.mjs, run with Redux Toolkit 2.13.0 in Node 22 - so every definition here matches what the code really does.

Worked example: A glossary you can come back to for the rest of the course - and one script that shows every term working.

ArchitectureThe words on the looptap a node to trace it

Lesson 9’s loop, labelled with the terms from this lesson. After the last box, the next user action starts the loop again at the top.

How to use this glossary

Read it once now, quickly - do not try to memorise it. The rest of the course uses these words exactly as defined here. When a later lesson uses a word you are not sure about, search this page for it.

Each table row gives the term, a simple definition, and a small code example. The full script at the end shows all of them working together.

1. The data

These words describe what Redux holds and how it is organised.

The data
StateThe app’s shared data at one moment: a plain JavaScript object. Module 2.
Initial stateThe value of a part of the state before any action has happened.
StoreThe one object that holds the state, runs the reducers and notifies subscribers. Module 2.
getStateRead the whole current state from the store.
Root reducer / state shapeThe reducer for the whole state, built from one reducer per key. Its keys are the shape of the state. Module 12.
SliceRedux Toolkit: one key of the state plus its reducers and action creators, made with createSlice. Module 4.

2. Describing changes

In Redux you do not change the state - you describe what happened. These words are about that description.

A good habit, recommended by the Redux style guide: name actions as events that already happened ("cart/added", "user/loggedOut"), not as commands ("setCart"). The part before the slash is the slice name; createSlice adds it for you.

Describing changes
ActionA plain object that describes what happened. It must have a type. Module 6.
TypeA string naming the event, usually "sliceName/eventName".
PayloadThe extra data an action carries. By convention it is called payload.
Action creatorA function that makes an action. createSlice makes one per reducer.

3. Making changes

These words describe how an action becomes a new state.

One point confuses everybody at first. Inside createSlice, reducers seem to change the state directly: state.items.push(...). Redux Toolkit uses a library called Immer, which records those changes on a draft copy and produces a brand-new state. In glossary.mjs we called the reducer with { items: ["Python"] }: it returned { items: ["Python", "Redux"] }, and the original object still had one item. Module 4 explains how.

Making changes
DispatchSend an action to the store. The only way to change state.
ReducerA function (state, action) -> new state. Modules 2-4.
Pure functionSame input -> same output, and no side effects: no server calls, no random values, no changing the input. Reducers must be pure.
Immutable updateMake a new object instead of changing the old one (Lesson 4).
ImmerThe library inside Redux Toolkit that lets reducers write "mutating" code safely.
Frozen stateRedux Toolkit freezes the state so accidental changes fail (Lesson 1).

4. Reading the state

These words are about getting data out of the store and into components.

Reading the state
SelectorA function that takes the whole state and returns one piece of it. Module 7.
SubscribeAsk the store to call a function after every dispatch. Returns a function to stop.
Providerreact-redux: makes the store available to all components below it. Module 5.
useSelectorreact-redux hook: run a selector, and re-render when its result changes. Module 5.
useDispatchreact-redux hook: get the store’s dispatch function in a component. Module 5.

5. Around the loop

These are the helpers that sit around the basic loop: for logging, async work, server data and debugging.

Around the loop
MiddlewareA function that sees every action before the reducers. Can log, delay, stop or add actions. Module 9.
ThunkA function you dispatch instead of an action, used for async work. Module 8.
createAsyncThunkRedux Toolkit: makes a thunk that dispatches pending, then fulfilled or rejected.
pending / fulfilled / rejectedThe three actions of an async thunk: started, succeeded, failed.
RTK QueryRedux Toolkit’s cache for server state (Lesson 3). Module 10.
Redux DevToolsA browser extension that shows every action and the state after it; configureStore connects to it in development.
Redux Toolkit (RTK)The official, modern way to write Redux: configureStore, createSlice and more. Module 4.
EnhancerAn advanced way to extend the store itself. Rarely written by hand. Module 4.

Every term, in one script

This script uses almost every word from the tables above. Read the comments in capital letters - each one names a term - and compare them with the output.

Look at the last two lines of the output. The subscriber was notified 3 times: once for cart/added, and once each for the thunk’s pending and fulfilled actions. After unsubscribe, another dispatch did not notify it, so the count stayed at 3.

glossary.mjs
import { configureStore, createAsyncThunk, createSlice } from "@reduxjs/toolkit"; // SLICE: one part of the state + its reducers + its action creators const cartSlice = createSlice({ name: "cart", initialState: { items: [] }, // INITIAL STATE reducers: { added(state, action) { // a REDUCER (case) state.items.push(action.payload); }, }, }); // ACTION CREATOR: a function that makes an action const { added } = cartSlice.actions; console.log("action creator: ", typeof added, "| added.type =", added.type); // ACTION: a plain object { type, payload } const action = added("Redux"); console.log("action: ", action); // REDUCER: (state, action) -> new state. Pure: same input, same output, no changes to the input const before = { items: ["Python"] }; const after = cartSlice.reducer(before, action); console.log("reducer: ", JSON.stringify(before), "->", JSON.stringify(after), "| input unchanged:", before.items.length === 1); // MIDDLEWARE: sees every action before the reducers const seen = []; const logger = () => (next) => (a) => { seen.push(a.type); return next(a); }; // THUNK: an async function you can dispatch const loadCart = createAsyncThunk("cart/load", async () => ["Python", "Redux"]); // STORE: holds the state; ROOT REDUCER built from the slices const store = configureStore({ reducer: { cart: cartSlice.reducer }, middleware: (getDefault) => getDefault().concat(logger), }); console.log("store state: ", JSON.stringify(store.getState())); // SUBSCRIBE: be told after every dispatch let notified = 0; const unsubscribe = store.subscribe(() => notified++); // DISPATCH: the only way to send an action store.dispatch(added("Docker")); console.log("after dispatch: ", JSON.stringify(store.getState()), "| subscribers notified:", notified); // SELECTOR: a function that reads a piece of state const selectItemCount = (state) => state.cart.items.length; console.log("selector: ", selectItemCount(store.getState())); // dispatching a thunk returns a promise const result = await store.dispatch(loadCart()); console.log("thunk dispatched: ", result.type, "| middleware saw:", seen.join(", ")); // IMMUTABLE: the state is frozen - you cannot edit it directly console.log("state is frozen: ", Object.isFrozen(store.getState().cart)); unsubscribe(); store.dispatch(added("Pandas")); console.log("after unsubscribe, notified still:", notified);
Output - node glossary.mjs
action creator: function | added.type = cart/added action: { type: 'cart/added', payload: 'Redux' } reducer: {"items":["Python"]} -> {"items":["Python","Redux"]} | input unchanged: true store state: {"cart":{"items":[]}} after dispatch: {"cart":{"items":["Docker"]}} | subscribers notified: 1 selector: 1 thunk dispatched: cart/load/fulfilled | middleware saw: cart/added, cart/load/pending, cart/load/fulfilled state is frozen: true after unsubscribe, notified still: 3
And when the thunk fails - checked
const loadCart = createAsyncThunk("cart/load", async () => { throw new Error("server down"); }); const result = await store.dispatch(loadCart()); console.log(result.type, "|", result.error.message); // cart/load/rejected | server down

Pairs people mix up

Most confusion in Redux comes from a few pairs of words that sound alike. Here they are side by side.

Not the same thing
Action vs action creatorAn action is an object: { type, payload }. An action creator is a function that returns one: added("Redux").
Action vs dispatchThe action is the message. dispatch is sending it. Creating an action does nothing until it is dispatched.
Reducer vs sliceA reducer is a function. A slice is a bundle made by createSlice: a reducer plus action creators plus a name.
Store vs stateThe store is the container with methods (dispatch, getState, subscribe). The state is the plain data inside it.
Selector vs useSelectorA selector is a plain function of the state. useSelector is the React hook that runs it and re-renders on change.
Middleware vs reducerMiddleware sees actions and may do side effects, but does not calculate state. Reducers calculate state and must have no side effects.
Thunk vs actionAn action is a plain object that reaches reducers. A thunk is a function; it never reaches reducers - it dispatches actions itself.

Naming conventions

Good names make Redux code read like a story of what happened. These are the conventions used in this course, following the Redux style guide.

How to name things
SlicesA noun for the feature.
Action types"slice/event", in the past tense - what happened, not what to do.
Action creatorsThe same event name, from createSlice.
SelectorsStart with select.
ThunksA verb for the work they start.

Common questions

Is "state" in Redux the same as "state" in useState? The idea is the same - data that changes and the screen depends on (Lesson 1). Redux state is shared by the whole app; useState belongs to one component.

Why do actions need a type string? Because every reducer is called for every action (Lesson 9), and the type is how each one decides whether the action concerns it. It also makes the action log readable.

Do I need to learn all of these now? No. Learn store, action, dispatch, reducer and selector now - they are the loop. The rest arrive with their own modules.

Is Redux Toolkit a different library from Redux? No. Redux Toolkit is the official package for writing Redux. It uses the Redux core inside; it removes repeated code and adds safe defaults.

The six words to know now

Store

Holds the state.

configureStore({ reducer })
Action

Describes what happened.

{ type: "cart/added", payload }
Dispatch

Sends an action to the store.

store.dispatch(action)
Reducer

Calculates the new state.

(state, action) => newState
Selector

Reads one piece of state.

(state) => state.cart.items
Middleware

Sees every action first.

(store) => (next) => (action) => next(action)

Try it yourself

The code does not change. Swap the content string and the program does something else entirely.

Run the glossary

“Run glossary.mjs. Change added("Docker") to two dispatches. How many times is the subscriber notified now?”

Prove purity

“Call cartSlice.reducer(before, action) twice with the same arguments. Are the results equal? Is before changed?”

Make it fail

“Make loadCart throw an error. Which action type does the middleware see last?”

Name it

“Rename an action in your own code from a command ("setUser") to an event ("user/loggedIn"). Does the action log read better?”

What usually goes wrong

Creating an action and forgetting to dispatch it

An action creator only makes an object. Nothing changes until you dispatch it.

✗ added("Docker");
✓ dispatch(added("Docker"));
Naming actions like commands

Name what happened, not what to do. Events read well in logs and let several slices react.

✗ "cart/setItems"
✓ "cart/itemAdded"
Side effects in a reducer

Reducers must be pure. Server calls, random values and timers go in thunks or middleware.

✗ added(state) { fetch("/api/cart"); }
✓ const loadCart = createAsyncThunk("cart/load", fetchCart);
Mixing up selector and useSelector

Write selectors as plain functions (easy to test and reuse), then pass them to useSelector.

✗ useSelector((state) => state.cart.items.filter(...))   // logic hidden in a component
✓ const selectVisibleItems = (state) => ...;
useSelector(selectVisibleItems);

Practice

Write these yourself before opening anything. Getting them wrong first is most of how this sticks.

1.

Match each term to its job: (1) reducer, (2) selector, (3) dispatch, (4) action, (5) middleware, (6) store. Jobs: (a) holds the state, (b) describes what happened, (c) sends an action, (d) calculates the new state, (e) reads a piece of state, (f) sees every action first.

Show hint

Follow the loop in the diagram.

Show solution
Answer
(1) reducer -> (d) calculates the new state (2) selector -> (e) reads a piece of state (3) dispatch -> (c) sends an action (4) action -> (b) describes what happened (5) middleware -> (f) sees every action first (6) store -> (a) holds the state
2.

In this line, name each part: dispatch(cartSlice.actions.added("Redux"))

Show hint

There are four things: a function that sends, a slice, an action creator, and a payload.

Show solution
Answer
dispatch - sends the action to the store cartSlice - the slice .actions.added - an action creator made by the slice "Redux" - the payload added("Redux") - returns the action { type: "cart/added", payload: "Redux" }
3.

Rename these actions as events: "setLoggedIn", "updateCartItems", "toggleSidebarOpen".

Show hint

slice/event, past tense - what happened?

Show solution
One possible answer
"setLoggedIn" -> "auth/loggedIn" "updateCartItems" -> "cart/itemAdded" (or itemRemoved - say which) "toggleSidebarOpen" -> "ui/sidebarToggled" (and ask Lesson 2: should it be local?)
Coding challenge

Label a store file

Copy this small store file and write the Redux term next to every line that has one. Then answer: which line would you change to log every action?

It should
  • Label: slice, initial state, reducer, action creator, store, root reducer, selector, dispatch, subscribe
  • Say where a logger middleware would be added
The file to label
import { configureStore, createSlice } from "@reduxjs/toolkit"; const savedSlice = createSlice({ name: "saved", initialState: { ids: [] }, reducers: { lessonSaved(state, action) { state.ids.push(action.payload); }, }, }); const { lessonSaved } = savedSlice.actions; const selectSavedCount = (state) => state.saved.ids.length; const store = configureStore({ reducer: { saved: savedSlice.reducer } }); store.subscribe(() => console.log(selectSavedCount(store.getState()))); store.dispatch(lessonSaved("redux-10"));
Show one solution
Answer
import { configureStore, createSlice } from "@reduxjs/toolkit"; const savedSlice = createSlice({ // SLICE name: "saved", // its name: action types start with "saved/" initialState: { ids: [] }, // INITIAL STATE reducers: { lessonSaved(state, action) { // REDUCER case (Immer draft) state.ids.push(action.payload); // action.payload = the PAYLOAD }, }, }); const { lessonSaved } = savedSlice.actions; // ACTION CREATOR const selectSavedCount = (state) => state.saved.ids.length; // SELECTOR const store = configureStore({ // STORE reducer: { saved: savedSlice.reducer }, // ROOT REDUCER: the state shape { saved } // middleware: (getDefault) => getDefault().concat(logger), <- add MIDDLEWARE here }); store.subscribe(() => console.log(selectSavedCount(store.getState()))); // SUBSCRIBE store.dispatch(lessonSaved("redux-10")); // DISPATCH an ACTION: { type: "saved/lessonSaved", payload: "redux-10" } // prints: 1

Key points

  • Store: holds the state. State: the plain data inside it.
  • Action: a plain object { type, payload } describing what happened. Action creator: a function that makes one.
  • Dispatch: the only way to send an action and change state.
  • Reducer: a pure function (state, action) -> new state. Slice: a reducer plus its action creators, from createSlice.
  • Selector: a function that reads a piece of state; useSelector runs it in a component.
  • Middleware: sees every action first. Thunk: a dispatched function for async work, which dispatches actions itself.
  • Name actions as past-tense events ("cart/added") and selectors with select.

Quick check before you move on

What is the difference between an action and an action creator?
An action is an object { type, payload }. An action creator is a function that returns one.
What does a reducer receive and return?
It receives the current state and an action, and returns the new state - without changing the old one.
What is a slice?
A bundle made by createSlice: one part of the state with its reducers and action creators.
What is a selector?
A function that takes the whole state and returns one piece of it.
What are the three actions of createAsyncThunk?
pending (started), fulfilled (succeeded) and rejected (failed).

Interview questions

Explain store, action, reducer and dispatch in one sentence each.

The store holds the application state; an action is a plain object describing what happened; a reducer is a pure function that computes the next state from the current state and an action; dispatch sends an action to the store, which runs the reducers.

What is a selector, and why use one?

A function that derives data from the state. Selectors keep state-reading logic in one reusable, testable place, hide the state shape from components, and with memoisation avoid unnecessary work and re-renders.

What is middleware in Redux?

A function wrapped around dispatch that sees every action before the reducers. It is where side effects, logging, analytics and async handling such as thunks live.

What is the difference between Redux and Redux Toolkit?

Redux is the core library. Redux Toolkit is the official way to use it: configureStore, createSlice, createAsyncThunk and RTK Query, with Immer for immutable updates and sensible defaults such as DevTools and the thunk middleware.

Quiz

  1. 1.

    What did added("Redux") return in glossary.mjs?

  2. 2.

    After calling the reducer with before = { items: ["Python"] }, was before changed?

  3. 3.

    How many times was the subscriber notified, and why?

  4. 4.

    Does a thunk ever reach a reducer?

  5. 5.

    Which is the better action type: "cart/setItems" or "cart/itemAdded"? Why?

Comments

Sign in to leave a comment. Your name and photo come from Google; nothing else is shared.

Loading comments...