Back to React
React
easy
mid

What is Redux, and how do you create a Redux Toolkit slice?

Redux is a predictable global state container based on a single store, read-only state, and pure reducers updating state via dispatched actions. Modern Redux uses Redux Toolkit: createSlice generates the reducer + action creators with Immer-powered 'mutating' syntax.

6 min read·~12 min to think through

Redux is a predictable state-management library — a single global store, state that's only changed by dispatching actions, and pure reducers that compute the next state. Its three principles:

  1. Single source of truth — one store holds app state.
  2. State is read-only — you change it only by dispatching an action (a { type, payload } object describing what happened).
  3. Changes via pure reducers(state, action) => newState, no side effects, no mutation.

The flow: dispatch(action) → reducer → new state → subscribed components re-render. The benefits are predictability, time-travel debugging, and a clear audit trail of every change.

Modern Redux = Redux Toolkit (RTK)

Classic Redux had a lot of boilerplate (action types, action creators, switch-statement reducers, immutable spread everywhere). Redux Toolkit is the official, recommended waycreateSlice collapses all of it.

Creating a slice

js
import { createSlice } from "@reduxjs/toolkit";

const counterSlice = createSlice({
  name: "counter",
  initialState: { value: 0 },
  reducers: {
    increment: (state) => {
      state.value += 1;           // "mutating" — Immer makes it immutable under the hood
    },
    decrement: (state) => {
      state.value -= 1;
    },
    incrementByAmount: (state, action) => {
      state.value += action.payload;
    },
  },
});

export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;

createSlice auto-generates the action creators and action types from the reducers keys. The "mutating" code is safe because RTK uses Immer — you write mutations, Immer produces an immutable update.

Wiring it up

js
// store.js
const store = configureStore({ reducer: { counter: counterReducer } });

// component
const value = useSelector((s) => s.counter.value);
const dispatch = useDispatch();
dispatch(increment());

For async, RTK has createAsyncThunk (or RTK Query for server data).

When (and when not) to use Redux

  • Good fit: large app, complex global client state shared widely, need for devtools/middleware/time-travel, a big team wanting a known pattern.
  • Often unnecessary: server state belongs in React Query/RTK Query, not hand-managed in Redux; small apps do fine with useState/Context/Zustand. Don't reach for Redux reflexively.

How to answer

"Redux is a predictable state container — single store, read-only state, pure reducers, changes via dispatched actions. In modern code I use Redux Toolkit: createSlice generates the reducer and action creators, and Immer lets me write 'mutating' updates safely. But I'd scope it — server state goes to RTK Query/React Query, and small apps don't need Redux at all."

Follow-up questions

  • How does Immer let you write 'mutating' reducers safely?
  • What does createSlice generate for you?
  • Why use RTK Query / React Query instead of Redux for server data?
  • When is Redux overkill?

Common mistakes

  • Using classic Redux boilerplate instead of Redux Toolkit.
  • Storing server data in Redux and hand-rolling caching/loading flags.
  • Mutating state in a plain reducer outside Immer's context.
  • Reaching for Redux on a small app that doesn't need it.

Performance considerations

  • useSelector re-renders a component when its selected slice changes — keep selectors narrow and memoized. configureStore includes good defaults. For server data, RTK Query dedupes and caches; rolling your own in reducers is slower to build and error-prone.

Edge cases

  • Async flows — createAsyncThunk or RTK Query.
  • Normalizing relational state (createEntityAdapter).
  • SSR store hydration.
  • Selector performance — memoized selectors (reselect).

Real-world examples

  • A counter or cart slice with createSlice; createAsyncThunk for an API call.
  • Large multi-team apps using RTK for structure + devtools, RTK Query for server state.

Senior engineer discussion

Seniors state the three Redux principles, show createSlice, and explain Immer enabling safe 'mutating' syntax. The senior signal is scoping: server state belongs in RTK Query/React Query, small apps don't need Redux, and selectors should be narrow/memoized — Redux is a tool with a fit, not a default.

Related questions