All TypeScript templates

React + Redux Toolkit

Modern Redux with RTK, slices, and RTK Query for data fetching.

DevZone Tools1,490 copiesUpdated Feb 28, 2026ReactReduxTypeScript
# CLAUDE.md — React + Redux Toolkit

## When to use Redux

- Use Redux Toolkit (RTK) when state is shared across many disconnected parts of the app, or when actions cause coordinated changes.
- For server cache, use RTK Query (or TanStack Query). Don't keep server data in slices unless you have a specific reason.
- For local component state, use `useState`/`useReducer`. Don't promote everything to global.

## Slices

- One slice per domain. File: `src/features/<domain>/<domain>Slice.ts`.
- Use `createSlice`. Reducers are written as if mutating — Immer handles immutability.
- Co-locate selectors in the same file. Export `selectX` functions; never read state shape from components.
- Action creators are auto-generated. Don't write them by hand.

## Store

- Define the store once in `src/app/store.ts`:
  ```ts
  export const store = configureStore({ reducer: { users: usersReducer, ... } })
  export type RootState = ReturnType<typeof store.getState>
  export type AppDispatch = typeof store.dispatch
  ```
- Wrap `useDispatch` and `useSelector` once with the typed versions:
  ```ts
  export const useAppDispatch: () => AppDispatch = useDispatch
  export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
  ```
- Components import the typed hooks, never the raw `useDispatch`.

## Async with createAsyncThunk

- Use `createAsyncThunk` only for actions that touch async work *and* need to be tracked in slice state (loading flag, error).
- For simple data fetching, prefer RTK Query.
- Three reducers per thunk: `pending`, `fulfilled`, `rejected`. Always handle `rejected` — never silently swallow.

## RTK Query

- One `api` slice per backend. `createApi({ baseQuery, endpoints })`.
- Tag-based invalidation: each query provides tags, each mutation invalidates them. Don't manually `refetch`.
- Co-locate endpoints with the feature. Re-export hooks from a feature index file.

## Selectors

- Use `createSelector` (Reselect, re-exported by RTK) for derived data.
- Inputs are simple state-getter selectors; the result function does the computation.
- Don't pass new objects/arrays through `useSelector` without `createSelector` — you'll re-render every state change.

## Don't

- Don't mutate state outside slice reducers. Immer only works inside `createSlice`.
- Don't dispatch from inside reducers. Reducers are pure.
- Don't put non-serializable values (Maps, Sets, class instances, Promises) in state.
- Don't store the same data in two slices. Pick the owner; let others read.

Other TypeScript templates