- Use `createSlice()` for reducers with Immer — write mutable-looking updates that produce immutable state. Action creators are generated automatically.
- Use `createAsyncThunk()` for API calls — handle `pending`, `fulfilled`, `rejected` states in `extraReducers` with proper loading/error UI.
- Use RTK Query (`createApi`) for data fetching — it handles caching, invalidation, optimistic updates, and TypeScript types end-to-end.
- Use `createAsyncThunk` for async operations (API calls). Handle `pending`, `fulfilled`, `rejected` states.
- Use RTK Query (`createApi`) for data fetching with automatic caching, invalidation, and loading states.
- Write selectors with `createSelector` (reselect) for memoized derived data.
- Use Immer (built into RTK) for "mutative" reducer logic: `state.items.push(item)` is safe.