Redux Toolkit and RTK Query patterns for state management. Use for global state, API caching, and complex state logic. Includes slices, thunks, and query endpoints.
Resources
1Install
npx skillscat add alicoder001/agent-skills/redux Install via the SkillsCat registry.
SKILL.md
Redux Toolkit & RTK Query
Modern Redux with RTK Query for data fetching.
Instructions
1. Store Setup
// store/index.ts
import { configureStore } from '@reduxjs/toolkit';
import { api } from './api';
import authReducer from './authSlice';
export const store = configureStore({
reducer: {
[api.reducerPath]: api.reducer,
auth: authReducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(api.middleware),
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;2. Create Slice
// store/authSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
interface AuthState {
user: User | null;
token: string | null;
}
const initialState: AuthState = {
user: null,
token: null,
};
export const authSlice = createSlice({
name: 'auth',
initialState,
reducers: {
setCredentials: (state, action: PayloadAction<{ user: User; token: string }>) => {
state.user = action.payload.user;
state.token = action.payload.token;
},
logout: (state) => {
state.user = null;
state.token = null;
},
},
});
export const { setCredentials, logout } = authSlice.actions;
export default authSlice.reducer;3. RTK Query API
// store/api.ts
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
export const api = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({
baseUrl: '/api',
prepareHeaders: (headers, { getState }) => {
const token = (getState() as RootState).auth.token;
if (token) {
headers.set('Authorization', `Bearer ${token}`);
}
return headers;
},
}),
tagTypes: ['User', 'Post'],
endpoints: (builder) => ({
getUsers: builder.query<User[], void>({
query: () => '/users',
providesTags: ['User'],
}),
getUser: builder.query<User, string>({
query: (id) => `/users/${id}`,
providesTags: (result, error, id) => [{ type: 'User', id }],
}),
createUser: builder.mutation<User, Partial<User>>({
query: (body) => ({
url: '/users',
method: 'POST',
body,
}),
invalidatesTags: ['User'],
}),
}),
});
export const { useGetUsersQuery, useGetUserQuery, useCreateUserMutation } = api;4. Using Queries
function UserList() {
const { data: users, isLoading, error } = useGetUsersQuery();
if (isLoading) return <Skeleton />;
if (error) return <Error />;
return (
<ul>
{users?.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}5. Using Mutations
function CreateUserForm() {
const [createUser, { isLoading }] = useCreateUserMutation();
const handleSubmit = async (data: UserFormData) => {
try {
await createUser(data).unwrap();
toast.success('User created!');
} catch (error) {
toast.error('Failed to create user');
}
};
return <form onSubmit={handleSubmit}>...</form>;
}6. Typed Hooks
// store/hooks.ts
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;