miniSerializeError function signature and interface
miniSerializeError is the default error serialization function used by createAsyncThunk, based on serialize-error. It takes any value as an argument. If the argument is an object such as an Error instance, it returns a plain JS SerializedError object that copies over the listed fields (name, message, stack, code). Otherwise, it returns a stringified form of the value as { message: String(value) }.
interface SerializedError {
name?: string
message?: string
stack?: string
code?: string
}
function miniSerializeError(value: any): SerializedError
copyWithStructuralSharing function signature and behavior
copyWithStructuralSharing is a utility that recursively merges two similar objects together, preserving existing references if the values appear to be the same. It is used internally to help ensure that re-fetched data keeps using the same references unless the new data has actually changed, avoiding unnecessary re-renders. If either input is not a plain JS object or array, the new value is returned.
function copyWithStructuralSharing<T>(oldObj: any, newObj: T): T
function copyWithStructuralSharing(oldObj: any, newObj: any): any
createNextState - re-export of immer produce function
createNextState is the default immutable update function from the immer library, re-exported from Redux Toolkit. It is also commonly referred to as produce.
nanoid example usage
import { nanoid } from '@reduxjs/toolkit'
console.log(nanoid())
// 'dgPXxUz_6fWIQBD8XmiSy'
current function from immer - snapshot state during draft
current is a function from the immer library. It takes a snapshot of the current state of a draft and finalizes it without freezing. It is useful for printing the current state during debugging. The output of current can be safely leaked outside the producer.
current function example usage
import { createReducer, createAction, current } from '@reduxjs/toolkit'
interface Todo {
//...
}
const addTodo = createAction<Todo>('addTodo')
const initialState = [] satisfies Todo[] as Todo[]
const todosReducer = createReducer(initialState, (builder) => {
builder.addCase(addTodo, (state, action) => {
state.push(action.payload)
console.log(current(state))
})
})
original function from immer - returns original object
original is a function from the immer library. It returns the original object. It is particularly useful for referential equality checks in reducers.
isDraft function from immer - checks if value is draft
isDraft is a function from the immer library. It checks whether a given value is a Proxy-wrapped draft state.
freeze function from immer - freezes draftable objects
freeze is a function from the immer library. It freezes draftable objects using the same mechanism as Object.freeze.
combineReducers - Redux re-export for convenience
combineReducers is Redux's combineReducers function, re-exported from Redux Toolkit for convenience. While configureStore calls this internally, you may wish to call it directly to compose multiple levels of slice reducers.
compose - Redux function composing functions right to left
compose is Redux's compose function. It composes functions from right to left. It is a functional programming utility. You might want to use it to apply several store custom enhancers or functions in a row.
bindActionCreators - Redux re-export for wrapping action creators
bindActionCreators is Redux's bindActionCreators function. It wraps action creators with dispatch() so that they dispatch immediately when called.
createStore - Redux re-export, not recommended for direct use
createStore is Redux's createStore function. It is re-exported from Redux Toolkit but you should not need to use it directly.
applyMiddleware - Redux re-export, not recommended for direct use
applyMiddleware is Redux's applyMiddleware function. It is re-exported from Redux Toolkit but you should not need to use it directly.
nanoid function - generates random ID
nanoid is an inlined copy of nanoid/nonsecure. It generates a non-cryptographically-secure random ID string. It is used by default by createAsyncThunk for request IDs and may be useful for other cases.
Serializability Middleware purpose
The serializability middleware is a custom middleware that detects if any non-serializable values have been included in state or dispatched actions, modeled after redux-immutable-state-invariant. Any detected non-serializable values will be logged to the console.
Serializability Middleware included by default
The serializability middleware is added to the store by default by configureStore and getDefaultMiddleware.
SerializableStateInvariantMiddlewareOptions interface
The SerializableStateInvariantMiddlewareOptions interface has the following properties: isSerializable (function, optional, defaults to isPlain(), checks if a value is serializable and applies recursively); getEntries (function, optional, defaults to undefined, retrieves entries from each value); ignoredActions (string array, optional, defaults to [], action types to ignore when checking serializability); ignoredActionPaths (string or RegExp array, optional, defaults to ['meta.arg', 'meta.baseQueryMeta'], dot-separated path strings or regexes to ignore); ignoredPaths (string or RegExp array, optional, defaults to [], dot-separated path strings or regexes to ignore); warnAfter (number, optional, defaults to 32ms, execution time warning threshold); ignoreState (boolean, optional, opts out of checking state); ignoreActions (boolean, optional, opts out of checking actions).
createSerializableStateInvariantMiddleware function
createSerializableStateInvariantMiddleware creates an instance of the serializability check middleware with the given options. It takes a SerializableStateInvariantMiddlewareOptions object as an argument and returns middleware. This function is typically used via getDefaultMiddleware and does not usually need to be called directly.
isPlain function
isPlain checks whether the given value is considered a 'plain value' or not. It returns true for undefined, null, strings, booleans, numbers, arrays, and plain objects. It returns false for Date objects, Map objects, and other similar class instances.
createSerializableStateInvariantMiddleware example with Immutable.JS
Example showing how to create a serializable middleware instance that treats Immutable.JS iterables as serializable: import { Iterable } from 'immutable'; import { configureStore, createSerializableStateInvariantMiddleware, isPlain, Tuple } from '@reduxjs/toolkit'; import reducer from './reducer'; const isSerializable = (value: any) => Iterable.isIterable(value) || isPlain(value); const getEntries = (value: any) => Iterable.isIterable(value) ? value.entries() : Object.entries(value); const serializableMiddleware = createSerializableStateInvariantMiddleware({ isSerializable, getEntries }); const store = configureStore({ reducer, middleware: () => new Tuple(serializableMiddleware) });
One API slice per base URL recommendation
Best practice is to have only one API slice per base URL that the application needs to communicate with. For example, if fetching from both /api/posts and /api/users, create a single API slice with /api/ as the base URL and separate endpoint definitions for posts and users.
RTK Query is built on Redux Toolkit core
RTK Query is built on top of the Redux Toolkit core and leverages RTK APIs like createSlice and createAsyncThunk to implement its capabilities.
RTK Query included in redux-toolkit package
RTK Query is included in the @reduxjs/toolkit package as an additional addon. It is not required to use RTK Query APIs when using Redux Toolkit.
createApi basic usage for RTK Query
createApi is used to define an RTK Query service. Example: export const pokemonApi = createApi({ reducerPath: 'pokemonApi', baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }), endpoints: (builder) => ({ getPokemonByName: builder.query<Pokemon, string>({ query: (name) => `pokemon/${name}`, }), }), });
fetchBaseQuery used with createApi
fetchBaseQuery is used to configure the base URL and other fetch options when creating an RTK Query API service. It is imported from '@reduxjs/toolkit/query/react'.
RTK Query generates auto-generated React hooks
RTK Query automatically generates React hooks based on the defined endpoints. These hooks are exported from the API service definition and can be used in functional components.
setupListeners for RTK Query refetch behaviors
setupListeners must be called to enable refetchOnFocus and refetchOnReconnect behaviors in RTK Query. It is imported from '@reduxjs/toolkit/query' and called with store.dispatch.
Query hook return values
RTK Query query hooks return an object containing: data (the fetched data), error (any error that occurred), isLoading (boolean indicating if initial request is in progress), isFetching (boolean indicating if any request is in progress), isSuccess (boolean indicating successful completion), and isError (boolean indicating an error occurred).
RTK Query dedupes requests automatically
RTK Query automatically deduplicates requests across components subscribing to the same query, ensuring the same data is used and performance optimizations are handled automatically.
injectEndpoints for code splitting RTK Query
The injectEndpoints property can be used to inject API endpoints from other files into a single API slice definition for maintainability purposes while keeping a centralized API slice.
original and isDraft functions re-exported from RTK
Redux Toolkit re-exports Immer's original and isDraft functions as of RTK 1.5.1. The original function retrieves the original data without any updates applied, and isDraft checks if a given value is a Proxy-wrapped draft.
Standalone getDefaultMiddleware and getType exports removed
In Redux Toolkit 2.0, the standalone getDefaultMiddleware export has been removed. Use the function passed to the middleware callback instead. The getType export has also been removed; use actionCreator.type static property instead.
action.type must be a string
In Redux 5.0, action.type must be a string. Attempting to dispatch an action with a non-string type will throw an error. This ensures actions are serializable and provide readable action history in Redux DevTools.
RTK Query API reducer and middleware must be added to store
When using RTK Query, the generated API object's reducer must be added to configureStore under the API's reducerPath key, and the API's middleware must be added to the middleware chain using concat() method.
useSelector hook replaces connect mapStateToProps
React-Redux useSelector hook is used instead of connect's mapStateToProps to select values from state. Each field from mapStateToProps becomes a separate useSelector call inside the component.
useDispatch hook replaces connect mapDispatchToProps
React-Redux useDispatch hook is used instead of connect's mapDispatchToProps to get the dispatch function. Action dispatching is done with callback functions defined inside the component that call dispatch with action creators.
React.memo prevents unnecessary re-renders with hooks
Unlike connect which prevents re-renders when props haven't changed, useSelector and useDispatch hooks are inside components so they cannot prevent React's normal rendering behavior. Wrap components with React.memo() to prevent unnecessary re-renders when parent components re-render.
Prefer RTK Query over createAsyncThunk for data fetching
Redux Toolkit documentation specifically recommends using RTK Query for data fetching rather than createAsyncThunk, as RTK Query provides a more complete solution with built-in caching and state management.
Infer AppDispatch type from store.dispatch
For TypeScript, infer the AppDispatch type by using typeof store.dispatch which correctly includes types for middleware-added functionality like thunks and other dispatch enhancements.
Create pre-typed useAppDispatch and useAppSelector hooks
For TypeScript, create pre-typed hook aliases using useDispatch.withTypes<AppDispatch>() and useSelector.withTypes<RootState>() and use these throughout the app instead of plain hooks to ensure correct types everywhere.
Legacy action type unions pattern should be avoided
Redux Toolkit documentation specifically recommends against manually defining types for individual actions and creating 'action type unions' to limit what can be dispatched. This pattern was common in legacy TypeScript Redux code but is unnecessarily verbose.
Modern Redux uses feature-based folder organization
Redux Toolkit and modern Redux patterns recommend organizing files by 'features' with related code living together in the same folder, rather than the older pattern of organizing by 'type of code' (actions, reducers, constants in separate folders).
Action names should use past tense event-style descriptions
Modern Redux patterns recommend naming actions in past tense using event-style names that describe 'a thing that happened', such as 'todoAdded' instead of imperative names like 'ADD_TODO'.
Start Redux migration by replacing createStore with configureStore
When migrating legacy Redux code to modern patterns, always start by replacing the legacy createStore call with configureStore. This is a one-time step that allows existing reducers and middleware to continue working while enabling development-mode checks for common mistakes.
Migrate legacy Redux incrementally, slice by slice
Legacy Redux codebases can be modernized incrementally by replacing one reducer and its actions at a time with createSlice, allowing old and new Redux code to coexist and work together.
Infer RootState type from store.getState return type
For TypeScript, infer the RootState type by using ReturnType<typeof store.getState> which automatically includes all slice state types and reflects any modifications to slice definitions.
RTK Query replaces data fetching boilerplate
Redux Toolkit's RTK Query is a data fetching and caching layer that eliminates the need to manually write actions, thunks, reducers, and selectors for data fetching. It handles loading state tracking, request deduplication, and cache lifecycle management internally.
RTK Query createApi defines endpoints and generates hooks
createApi accepts configuration with baseQuery and endpoints. Endpoints are defined as query or mutation operations. The API object exposes generated React hooks for each endpoint with naming pattern useEndpointNameQuery or useEndpointNameMutation.
SerializableStateInvariantMiddlewareOptions interface
SerializableStateInvariantMiddlewareOptions has properties: getEntries (optional, (value: any) => [string, any][]), ignoredActionPaths (optional, (string | RegExp)[]), ignoredActions (optional, string[]), ignoredPaths (optional, (string | RegExp)[]), ignoreState (optional, boolean), isSerializable (optional, (value: any) => boolean), warnAfter (optional, number).
nanoid export
nanoid is an exported function with signature: (size?: number) => string. Generates a unique ID string.
unwrapResult function
unwrapResult<R extends UnwrappableAction>(action: R): UnwrappedActionPayload<R>. Extracts the payload from an async thunk result, throwing if the action was rejected.
EnhancedStore interface
EnhancedStore<S, A, M> extends Store<S, A> and has dispatch property of type Dispatch<A> & DispatchForMiddlewares<M>.
createAction function signature with prepare
createAction has two overloads: (1) createAction<P = void, T extends string = string>(type: T): PayloadActionCreator<P, T>, and (2) createAction<PA extends PrepareAction<any>, T extends string = string>(type: T, prepareAction: PA): PayloadActionCreator<ReturnType<PA>['payload'], T, PA>.
PayloadAction type structure
PayloadAction<P = void, T extends string = string, M = never, E = never> is an object with payload: P and type: T, optionally including meta: M (if M is not never) and error: E (if E is not never).
PayloadActionCreator type definition
PayloadActionCreator<P, T, PA> is determined by whether PA is provided (uses _ActionCreatorWithPreparedPayload<PA, T>) or by the type of P: any uses ActionCreatorWithPayload<any, T>, unknown or non-inferrable uses ActionCreatorWithNonInferrablePayload<T>, void uses ActionCreatorWithoutPayload<T>, optional uses ActionCreatorWithOptionalPayload<P, T>, otherwise ActionCreatorWithPayload<P, T>.
PrepareAction type
PrepareAction<P> is one of: (...args: any[]) => {payload: P}, (...args: any[]) => {payload: P, meta: any}, (...args: any[]) => {payload: P, error: any}, or (...args: any[]) => {payload: P, meta: any, error: any}.
CaseReducer type
CaseReducer<S = any, A extends Action = UnknownAction> is a function with signature: (state: Draft<S>, action: A) => S | void | Draft<S>.
ActionReducerMapBuilder interface methods
ActionReducerMapBuilder<State> has methods: addCase (with two overloads: accepts ActionCreator with CaseReducer, or accepts Type string with CaseReducer), addMatcher (accepts TypeGuard<A> or boolean function with CaseReducer, returns Omit<ActionReducerMapBuilder<State>, 'addCase'>), addDefaultCase (accepts CaseReducer<State, UnknownAction>, returns {}).
miniSerializeError constant
miniSerializeError is an exported function that serializes error values: (value: any) => SerializedError.