new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Redux Toolkit · API · all subjects

createslice api

18 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Slice interface properties

Slice<State, CaseReducers, Name> has the following properties: actions (CaseReducerActions<CaseReducers>), caseReducers (SliceDefinedCaseReducers<CaseReducers>), getInitialState (() => State), name (Name), reducer (Reducer<State>).

CreateSliceOptions interface properties

CreateSliceOptions<State, CR, Name> has the following properties: extraReducers (CaseReducers<NoInfer<State>, any> | ((builder: ActionReducerMapBuilder<NoInfer<State>>) => void), optional), initialState (State | (() => State), required), name (Name, required), reducers (ValidateSliceCaseReducers<State, CR>, required).

createSlice function signature and return type

createSlice is a generic function with signature: createSlice<State, CaseReducers extends SliceCaseReducers<State>, Name extends string = string>(options: CreateSliceOptions<State, CaseReducers, Name>): Slice<State, CaseReducers, Name>. It accepts CreateSliceOptions and returns a Slice object.

Migrate reducers incrementally as you touch them

When a legacy reducer requires editing, migrate that reducer to createSlice at that time instead of adding more legacy code to it. This prevents accumulating new legacy patterns during the migration period.

createSlice example with multiple reducers and typed actions

Example createSlice migration with typed state and actions: createSlice({ name: 'todos', initialState: { items: [] as { id: string; text: string; completed: boolean }[] }, reducers: { todoAdded(state, action: { payload: { id: string; text: string } }) { state.items.push({ ...action.payload, completed: false }) }, todoToggled(state, action: { payload: { id: string } }) { const todo = state.items.find((item) => item.id === action.payload.id); if (todo) { todo.completed = !todo.completed } } } }). Shows Immer-based mutation directly on state.

Selector factory pattern instead of createSlice.selectors

If a selector depends on caller-specific arguments and must be memoized separately for each caller, create a selector factory outside of createSlice.selectors. createSlice.selectors provides a single selector instance, not a factory. Use selector factories when memoization must be per-caller rather than global.

getSelectors for alternate mounting points

Call getSelectors on a slice with a selector function to remap selectors when the slice is not mounted at its default reducerPath. The selector function receives the root state and returns the slice state. Example: counterSlice.getSelectors((state) => state.customCounter) allows selectValue to work when the counter slice is mounted at state.customCounter instead of the default location.

RTK 2 extraReducers builder pattern required

RTK 2 removed object-form extraReducers syntax. Use builder form: extraReducers: (builder) => { builder.addCase(asyncAction.fulfilled, (state, action) => { ... }) }. The old object syntax with computed property keys is no longer supported.

Avoid hand-written switch reducers in RTK applications

Hand-written switch statement reducers should not be the default in Redux Toolkit code. Use createSlice instead, which handles action creation, reducer bundling, and Immer integration. Hand-written reducers are an escape hatch only for proven bottlenecks.

Slice selectors property in createSlice

The createSlice function accepts a selectors property that defines memoized selector functions scoped to that slice. Selectors are extracted via slice.selectors and keep state-location knowledge next to the slice definition.

Slice reducers receive create object with builder methods

When buildCreateSlice is configured with asyncThunkCreator, the reducers property becomes a function receiving a create object. The create object provides methods like reducer() for simple reducers and asyncThunk() for async lifecycle handlers.

Do not let slice boundaries fossilize

Avoid keeping unrelated data welded together in a single slice indefinitely. When unrelated data is in the same slice, every change point gets noisier and harder to manage. Split or merge slices as actual access patterns demand over time.

Re-size slices when access patterns change

Revisit slice boundaries over time as the application evolves. Unrelated data should be split into separate slices, and data that is constantly stitched together in every component should be moved closer together in the state tree.

createSlice uses Immer to enable immutable updates with mutating syntax

The createSlice function lets you write reducers that use the Immer library to enable writing immutable updates using mutating JavaScript syntax like state.value = 123, with no spreads needed. It also automatically generates action creator functions for each reducer and generates action type strings internally based on your reducer's names. It works great with TypeScript.

Example: Legacy hand-written Redux reducer with switch statement

Prior to Redux Toolkit, reducers were typically written with a switch statement and manual updates, along with hand-written action creators and action type constants. Example: const ADD_TODO = 'ADD_TODO' const TODO_TOGGLED = 'TODO_TOGGLED' export const addTodo = (text) => ({ type: ADD_TODO, payload: { text, id: nanoid() }, }) export const todoToggled = (id) => ({ type: TODO_TOGGLED, payload: { id }, }) export const todosReducer = (state = [], action) => { switch (action.type) { case ADD_TODO: return state.concat({ id: action.payload.id, text: action.payload.text, completed: false, }) case TODO_TOGGLED: return state.map((todo) => { if (todo.id !== action.payload.id) return todo return { ...todo, completed: !todo.completed, } }) default: return state } }

Example: Modern Redux with createSlice

With Redux Toolkit createSlice, the same todos reducer can be written much more concisely. Example: import { createSlice } from '@reduxjs/toolkit' const todosSlice = createSlice({ name: 'todos', initialState: [], reducers: { todoAdded(state, action) { state.push({ id: action.payload.id, text: action.payload.text, completed: false, }) }, todoToggled(state, action) { const todo = state.find((todo) => todo.id === action.payload) todo.completed = !todo.completed }, }, }) export const { todoAdded, todoToggled } = todosSlice.actions export default todosSlice.reducer

createReducer accepts action types lookup table with Immer

createReducer() lets you supply a lookup table of action types to case reducer functions, rather than writing switch statements. It automatically uses the Immer library to let you write simpler immutable updates with normal mutative code, like state.todos[3].completed = true.

createSlice combines createReducer and createAction

createSlice() combines createReducer() + createAction(). It accepts an object of reducer functions, a slice name, and an initial state value, and automatically generates a slice reducer with corresponding action creators and action types.

Give your agent this brain