Redux & Redux Toolkit — App-Wide State ManagementEntry 6 of 11

Redux Toolkit: createSlice

createSlice defines one piece of state (a slice) with its initial state and reducers, and auto-generates the matching action creators.

Notes

  • A slice groups related state and logic: counter, auth, cart.
  • Each key in reducers becomes both a reducer case and an action creator.
  • RTK uses Immer, so you can write "mutating" code (state.counter++). Immer turns it into an immutable update.
  • Action types are generated as sliceName/reducerName (e.g. counter/increment), so no hand-written type strings.
  • Calling an action creator with an argument puts it in action.payload.

What / Why / When

What

Reducer + actions in one declaration.

Why

Removes the switch, the type strings, and manual spreading.

When

Every new Redux project. RTK is the officially recommended way to write Redux.

Code compare

React
// store/counter-slice.tsimport { createSlice, type PayloadAction } from "@reduxjs/toolkit";​type CounterState = { counter: number; showCounter: boolean };​const initialState: CounterState = { counter: 0, showCounter: true };​const counterSlice = createSlice({  name: "counter",  initialState,  reducers: {    increment(state) {      state.counter++; // ✅ safe: Immer handles immutability    },    decrement(state) {      state.counter--;    },    increase(state, action: PayloadAction<number>) {      state.counter += action.payload;    },    toggleCounter(state) {      state.showCounter = !state.showCounter;    },  },});​export const counterActions = counterSlice.actions;export default counterSlice.reducer;
Angular
// store/counter.actions.tsimport { createActionGroup, emptyProps, props } from "@ngrx/store";​export const CounterActions = createActionGroup({  source: "Counter",  events: {    Increment: emptyProps(),    Decrement: emptyProps(),    Increase: props<{ amount: number }>(),    "Toggle Counter": emptyProps(),  },});

Differences and gotchas

  • Mutation: RTK allows state.counter++ (Immer). NgRx has no Immer; reducers must return new objects with spread.
  • Actions: RTK generates actions from reducers. NgRx declares actions separately with createActionGroup, so one action can be handled by several reducers and effects.
  • Selectors: createFeature generates a selector per state property. RTK has no equivalent; you write state => state.counter.counter.
  • ❌ In RTK, don't mutate and return a new value in the same reducer. Do one or the other.

Quick reference

TaskRedux ToolkitNgRx
Define state + reducerscreateSlice({ name, initialState, reducers })createFeature({ name, reducer: createReducer(...) })
Actionsslice.actions (auto)createActionGroup()
Payloadaction.payloadNamed props: { amount }
ImmutabilityImmer (mutate freely)Manual spread
Action type formatcounter/increment[Counter] Increment