When to use this skill
Use this skill whenever the user wants to:
- Manage global application state with Redux or Redux Toolkit
- Create slices with
createSliceand configure the store withconfigureStore - Handle asynchronous logic with
createAsyncThunkor RTK Query - Use
useSelectoranduseDispatchhooks in React components - Implement middleware, selectors, and normalized state patterns
- Migrate from classic Redux to Redux Toolkit
How to use this skill
Workflow
- Identify the state domain the user needs to manage
- Create a slice using Redux Toolkit's
createSlice - Configure the store and provide it to the React app
- Connect components using
useSelectoranduseDispatch
1. Create a Slice
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
interface CounterState {
value: number;
}
const initialState: CounterState = { value: 0 };
const counterSlice = createSlice({
name: 'counter',
initialState,
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;
2. Configure the Store
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';
export const store = configureStore({
reducer: {
counter: counterReducer,
},
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
3. Use in Components
import { useSelector, useDispatch } from 'react-redux';
import { RootState, AppDispatch } from './store';
import { increment, decrement } from './counterSlice';
export function Counter() {
const count = useSelector((state: RootState) => state.counter.value);
const dispatch = useDispatch<AppDispatch>();
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch(increment())}>+</button>
<button onClick={() => dispatch(decrement())}>-</button>
</div>
);
}
4. Async Thunk
import { createAsyncThunk } from '@reduxjs/toolkit';
export const fetchUsers = createAsyncThunk('users/fetch', async () => {
const response = await fetch('/api/users');
return response.json();
});
Best Practices
- Keep state flat and normalized; split reducers by domain
- Use Redux Toolkit (
createSlice,configureStore) instead of hand-written boilerplate - Actions and reducers should be pure functions with no side effects
- Use
createAsyncThunkor RTK Query for async operations; never fetch in reducers - Use typed hooks (
useAppSelector,useAppDispatch) for type-safe access - Only store serializable data in the Redux store
Resources
- Redux Toolkit: https://redux-toolkit.js.org/
- React Redux: https://react-redux.js.org/
- RTK Query: https://redux-toolkit.js.org/rtk-query/overview
Keywords
redux, Redux Toolkit, createSlice, configureStore, createAsyncThunk, RTK Query, useSelector, useDispatch, state management, middleware, store, actions, reducers