---
applyTo: "src/**/*.ts,src/**/*.tsx"
description: Redux Toolkit and RTK Query conventions
---

# Redux Toolkit

- Modern Redux only: `configureStore`, `createSlice`, `createAsyncThunk` or RTK Query. No hand-written action types, `switch` reducers, `connect()` or `redux-thunk` setup.
- Store in `src/app/store.ts`; export `RootState` and `AppDispatch` from it. Use typed hooks from `src/app/hooks.ts`: `useAppDispatch = useDispatch.withTypes<AppDispatch>()` and `useAppSelector = useSelector.withTypes<RootState>()`.
- One slice per feature in `src/features/<feature>/<feature>Slice.ts`. "Mutating" code inside reducers is fine (Immer); never mutate state outside a reducer.
- Keep state normalized; use `createEntityAdapter` for collections.
- Selectors live next to the slice. Memoize derived data with `createSelector`; never return a new array from `useAppSelector` without it.
- Server data goes through RTK Query: one `createApi` per backend in `src/services/api.ts` with `fetchBaseQuery`, endpoints added via `injectEndpoints`. Use `providesTags`/`invalidatesTags` instead of manual refetching.
- Use generated hooks (`useGetPostsQuery`, `useAddPostMutation`) and handle `isLoading`, `isError`, `error` in the component.
- Keep non-serializable values (class instances, Dates, Promises) out of state; store ISO strings.

## Tests
Test reducers as pure functions and components with a real store built by a `setupStore(preloadedState)` helper.
