createSlice accepts single config object parameter
createSlice accepts a single configuration object parameter with the following properties: name (string, required), initialState (State, required), reducers (Record<string, ReducerFunction | ReducerAndPrepareObject>, required), extraReducers (optional builder callback function), reducerPath (optional string, defaults to name), and selectors (optional Record<string, selector function>).
createSlice name parameter
The name parameter is a string used to generate action type constants as a prefix. Generated action type constants will use this name as a prefix and will show up in Redux DevTools Extension.
createSlice initialState parameter
The initialState parameter is the initial state value for the slice. It may also be a lazy initializer function that returns an initial state value when called. This will be used whenever the reducer is called with undefined as its state value, and is primarily useful for reading initial state from localStorage.
createSlice reducers parameter contains case reducers
The reducers parameter is an object containing Redux case reducer functions intended to handle specific action types. Keys in the object are used to generate string action type constants. These case reducers may safely mutate the state they are given using Immer. The object is passed to createReducer internally.
createSlice reducers with prepare callback
To customize the payload value of an action creator, the reducer field value should be an object with two properties: reducer (the case reducer function) and prepare (the prepare callback function). The prepare function customizes how the payload is created before being passed to the reducer.
createSlice reducers creator callback notation
Alternatively, the reducers field can be a callback function that receives a create object. This allows creating async thunks as part of the slice using create.asyncThunk, create.reducer, and create.preparedReducer methods.
createSlice create.reducer method
create.reducer is a method used in the reducers creator callback notation that accepts a reducer function and returns a standard slice case reducer.
createSlice create.preparedReducer method
create.preparedReducer is a method used in the reducers creator callback notation that accepts two parameters: prepareAction (the prepare callback) and reducer (the slice case reducer). The action type passed to the case reducer is inferred from the prepare callback's return value.
createSlice create.asyncThunk method requires setup
To use create.asyncThunk within createSlice, extra setup is required to avoid adding createAsyncThunk to the bundle size. Import buildCreateSlice and asyncThunkCreator, then create a custom createSlice by calling buildCreateSlice({ creators: { asyncThunk: asyncThunkCreator } }).
createSlice create.asyncThunk parameters
create.asyncThunk accepts two parameters: payloadCreator (the thunk payload creator function) and config (optional configuration object). The config object can contain case reducers for lifecycle actions (pending, fulfilled, rejected) and a settled reducer that runs for both fulfilled and rejected actions. The config object can also contain options passed to createAsyncThunk.
createSlice create.asyncThunk case reducers attached to caseReducers
Each case reducer provided to create.asyncThunk configuration (pending, fulfilled, rejected, settled) will be attached to the slice's caseReducers object, for example slice.caseReducers.fetchTodo.fulfilled.
createSlice create.asyncThunk typing considerations
Typing for create.asyncThunk works similarly to createAsyncThunk, but state and dispatch cannot be provided as part of ThunkApiConfig as this causes circular types. Instead, cast types manually when needed (getState() as RootState). A withTypes helper is provided for common thunk API configuration options.
createSlice extraReducers allows handling other action types
The extraReducers field allows createSlice to respond and update its own state in response to action types defined elsewhere (such as actions from other createSlice calls, createAsyncThunk, or other actions). Unlike reducers, extraReducers will not generate new action types or action creators. Each case reducer in extraReducers is wrapped in Immer and may use mutating syntax.
createSlice extraReducers builder callback notation
The extraReducers field uses a builder callback notation similar to createReducer to define handlers for specific action types. It supports builder.addCase, builder.addMatcher, and builder.addDefaultCase methods with better TypeScript support for inferring action types from action creators.
createSlice reducers vs extraReducers action type precedence
If two fields from reducers and extraReducers happen to end up with the same action type string, the function from reducers will be used to handle that action type.
createSlice reducerPath parameter
The reducerPath parameter indicates a preference for where the slice should be located in the store state. It defaults to the value of the name parameter. This is used by combineSlices and the default generated slice.selectors.
createSlice selectors parameter
The selectors parameter is an optional object of selectors that receive the slice state as their first parameter and any other parameters. Each selector will have a corresponding key in the resulting selectors object on the return value.
createSlice selectors circular type issue
Selectors that use other selectors can cause circular type inference problems if no return type is provided. This can be fixed by providing an explicit return type for the selector, breaking the type inference cycle.
createSlice return value structure
createSlice returns an object with properties: name (string), reducer (ReducerFunction), actions (Record<string, ActionCreator>), caseReducers (Record<string, CaseReducer>), getInitialState (function), reducerPath (string), selectSlice (Selector), selectors (Record<string, Selector>), getSelectors (function receiving selectState callback), and injectInto (function for combineSlices integration).
createSlice actions property
Each function defined in the reducers argument has a corresponding action creator generated using createAction and included in the result's actions field using the same function name.
createSlice reducer property
The generated reducer function is suitable for passing to the Redux combineReducers function as a slice reducer.
createSlice caseReducers property
Functions passed to the reducers parameter can be accessed through the caseReducers return field. This can be particularly useful for testing or direct access to reducers created inline.
createSlice getInitialState function
The getInitialState function provides access to the initial state value given to the slice. If a lazy state initializer function was provided, it will be called and a fresh value returned.
createSlice injectInto function
The injectInto function creates an instance of the slice that is aware it has been injected, used with combineSlices for slice integration.
createSlice selectSlice selector
The slice has a selectSlice selector attached that assumes the slice is located under rootState[slice.reducerPath]. The slice.selectors uses this selector to wrap each of the selectors provided.
createSlice selectors wrapped selector unwrapped property
The original selector passed is attached to the wrapped selector as .unwrapped. For example, a wrapped createSelector selector will have access to .unwrapped.recomputations.
createSlice getSelectors method with selectState callback
slice.getSelectors is called with a single parameter, a selectState callback function that receives the store root state and returns the slice state. This allows custom selector wrapping based on where the slice is mounted.
createSlice getSelectors without selectState callback
If no selectState callback is passed to getSelectors, selectors will be returned as is, expecting the slice state as their first parameter (equivalent to calling slice.getSelectors(state => state)).
createSlice getSelectors equivalent to using selectSlice
slice.selectors is the equivalent of calling slice.getSelectors(slice.selectSlice) or slice.getSelectors((state: RootState) => state[slice.reducerPath]).
createSlice basic example with counter
Example: import { createSlice } from '@reduxjs/toolkit'; import type { PayloadAction } from '@reduxjs/toolkit'; interface CounterState { value: number }; const initialState = { value: 0 } satisfies CounterState as CounterState; const counterSlice = createSlice({ name: 'counter', initialState, reducers: { increment(state) { state.value++ }, decrement(state) { state.value-- }, incrementByAmount(state, action: PayloadAction<number>) { state.value += action.payload } } }); export const { increment, decrement, incrementByAmount } = counterSlice.actions; export default counterSlice.reducer;
createSlice with prepare callback example
Example: const todosSlice = createSlice({ name: 'todos', initialState: [] as Item[], reducers: { addTodo: { reducer: (state, action: PayloadAction<Item>) => { state.push(action.payload) }, prepare: (text: string) => { const id = nanoid(); return { payload: { id, text } } } } } });
createSlice with creator callback notation example
Example: const todosSlice = createSlice({ name: 'todos', initialState: { loading: false, todos: [] } satisfies TodoState as TodoState, reducers: (create) => ({ deleteTodo: create.reducer<number>((state, action) => { state.todos.splice(action.payload, 1) }), addTodo: create.preparedReducer((text: string) => { const id = nanoid(); return { payload: { id, text } } }, (state, action) => { state.todos.push(action.payload) }), fetchTodo: create.asyncThunk(async (id: string, thunkApi) => { const res = await fetch(`myApi/todos?id=${id}`); return (await res.json()) as Item }, { pending: (state) => { state.loading = true }, rejected: (state, action) => { state.loading = false }, fulfilled: (state, action) => { state.loading = false; state.todos.push(action.payload) } }) }) });
createSlice with extraReducers example
Example: const counter = createSlice({ name: 'counter', initialState: 0 satisfies number as number, reducers: { increment: (state) => state + 1, decrement: (state) => state - 1 }, extraReducers: (builder) => { builder.addCase(incrementBy, (state, action) => { return state + action.payload }) builder.addCase(decrementBy, (state, action) => { return state - action.payload }) } });
createSlice action type generation
Action types generated from reducer keys use the pattern 'sliceName/reducerKey'. For example, a slice named 'counter' with a reducer key 'increment' generates the action type 'counter/increment'.
createSlice requires name, initialState, and reducers
Creating a slice requires a string name to identify the slice, an initial state value, and one or more reducer functions to define how the state can be updated.
createSlice example with counter reducer
Example: export const counterSlice = createSlice({ name: 'counter', initialState: { value: 0 }, reducers: { increment: (state) => { state.value += 1 }, decrement: (state) => { state.value -= 1 }, incrementByAmount: (state, action: PayloadAction<number>) => { state.value += action.payload } } }); export const { increment, decrement, incrementByAmount } = counterSlice.actions; export default counterSlice.reducer;
createSlice generates action creators and reducer
Once a slice is created with createSlice, you can export the generated Redux action creators and the reducer function for the whole slice.
createSlice uses Immer for immutable updates
Redux Toolkit's createSlice uses Immer inside to allow writing 'mutating' update logic that becomes correct immutable updates. Reducer functions may 'mutate' the state using Immer.
PayloadAction type for action payloads
PayloadAction is imported from @reduxjs/toolkit and used to type action payloads in reducer functions. Example: action: PayloadAction<number>
Define slice state type interface for createSlice
Each slice file should define a TypeScript interface type for its initial state value so that createSlice can correctly infer the type of state in each case reducer. For example: 'interface CounterState { value: number }'.
Use PayloadAction type for reducer actions with payload
All generated actions should be defined using the 'PayloadAction<T>' type from Redux Toolkit, which takes the type of the 'action.payload' field as its generic argument. For example: 'incrementByAmount: (state, action: PayloadAction<number>)' means the action creator requires a number argument.
Workaround for TypeScript tightening initial state type
In some cases, TypeScript may unnecessarily tighten the type of the initial state. This can be worked around by casting the initial state using 'satisfies' and 'as' instead of declaring the variable type: 'const initialState = { value: 0 } satisfies CounterState as CounterState'.
createSlice uses Immer automatically
Redux Toolkit's createSlice uses createReducer inside, so it is also safe to write code that mutates state in reducer functions defined in createSlice. This applies even if case reducer functions are defined outside of the createSlice call.
ESLint no-param-reassign rule with Immer reducers
Many ESLint configs include the no-param-reassign rule which may warn about mutations to nested fields in Immer-powered reducers. To resolve this, configure ESLint to ignore mutations and assignment to a parameter named state only in slice files using an override with props: false.
createSlice.extraReducers builder form required in RTK 2.0
The object syntax for createSlice.extraReducers has been removed in Redux Toolkit 2.0. You must use the builder callback form instead. For example, instead of extraReducers: { [todoAdded]: (state, action) => {} }, use extraReducers: (builder) => { builder.addCase(todoAdded, (state, action) => {}) }.
createSlice callback syntax for reducers and async thunks
Redux Toolkit 2.0 adds an optional callback syntax for the reducers field in createSlice, allowing you to define thunks directly inside the slice. This requires setting up a custom createSlice using buildCreateSlice with asyncThunk support. The callback receives a create object with methods: create.reducer() for normal reducers, create.preparedReducer() for reducers with prepare callbacks, and create.asyncThunk() for async thunks. This is entirely optional; the object syntax for basic reducers still works.
createSlice with async thunks callback syntax example
Example of using the new callback syntax with async thunks in createSlice:
const createAppSlice = buildCreateSlice({ creators: { asyncThunk: asyncThunkCreator } })
const todosSlice = createAppSlice({
name: 'todos',
initialState: { loading: false, todos: [], error: null },
reducers: (create) => ({
deleteTodo: create.reducer((state, action: PayloadAction<number>) => {
state.todos.splice(action.payload, 1)
}),
addTodo: create.preparedReducer(
(text: string) => {
const id = nanoid()
return { payload: { id, text } }
},
(state, action) => {
state.todos.push(action.payload)
},
),
fetchTodo: create.asyncThunk(
async (id: string, thunkApi) => {
const res = await fetch(`myApi/todos?id=${id}`)
return (await res.json())
},
{
pending: (state) => { state.loading = true },
rejected: (state, action) => { state.error = action.payload ?? action.error },
fulfilled: (state, action) => { state.todos.push(action.payload) },
settled: (state, action) => { state.loading = false },
},
),
}),
})
export const { addTodo, deleteTodo, fetchTodo } = todosSlice.actions
createSlice generates action creators automatically
createSlice automatically generates action creators with names derived from the reducer function names defined in the reducers object. These generated action creators are exported from the actions property of the slice and can be used with dispatch.
createSlice uses Immer for immutable updates
createSlice uses the Immer library internally, allowing reducer logic to be written with direct mutations of the state draft. The mutations appear to modify state but are actually creating immutable updates under the hood. No return statement is needed in reducers when using this pattern.
createSlice actions use action.payload for arguments
In createSlice reducers, action creators automatically pass any arguments as the action.payload field. Single values are passed directly as payload, while multiple values should be passed as an object literal or handled with the prepare notation.
createSlice supports prepare notation for action creator customization
createSlice reducers can use a prepare notation to customize how action creators handle multiple separate arguments and how the payload is constructed. This is useful for generating unique IDs or doing additional work in action creators.
createSlice exports reducer as default export
The createSlice API returns a slice object with a reducer property that should be exported as the default export from the slice file and passed to configureStore.
createSlice extraReducers handles actions from other sources like createAsyncThunk
createSlice accepts an extraReducers option for handling actions generated outside the slice, such as those from createAsyncThunk. extraReducers uses a builder API with addCase() method to handle specific action types and update state accordingly.
Use PayloadAction type for action reducer parameters
In createSlice reducers, use PayloadAction<YourPayloadType> to type the action parameter, which enables correct type inference for action.payload and generated action creators' argument types.
Declare slice state type separately from initialState
For TypeScript with createSlice, declare and export a type for the slice state (e.g., export type TodosState = ...) separately from the initialState variable. This enables proper type inference for the state parameter in reducers.
createSlice generates action creators and reducer
createSlice takes a configuration object with `name`, `initialState`, and `reducers` properties, and returns an object with `name`, `actions`, and `reducer` properties. It auto-generates action types and action creators based on the reducer function names. Example: `const postsSlice = createSlice({ name: 'posts', initialState: [], reducers: { createPost(state, action) {}, updatePost(state, action) {}, deletePost(state, action) {} } })`
createSlice action type naming convention
createSlice generates action types in the format 'sliceName/reducerFunctionName'. For example, a reducer function named `createPost` in a slice named 'posts' generates an action type of 'posts/createPost'.
createSlice extracts actions and reducer
To export actions and reducer from a slice, destructure them from the slice object: `const { actions, reducer } = postsSlice`. Then you can further destructure individual action creators from actions: `export const { createPost, updatePost, deletePost } = actions`. Export the reducer as a default or named export.
createSlice with extraReducers for async thunks
createSlice accepts an `extraReducers` option (a builder callback) to handle additional action types, typically from async thunks created with createAsyncThunk. Example: `extraReducers: (builder) => { builder.addCase(fetchUserById.fulfilled, (state, action) => { state.entities.push(action.payload) }) }`
createSlice action type inference
createSlice creates actions and reducer automatically, so type safety is built-in. Action types can be provided inline: const slice = createSlice({ name: 'test', initialState: 0, reducers: { increment: (state, action: PayloadAction<number>) => state + action.payload } })