Redux Toolkit
You are an expert in Redux Toolkit for state management in React and Next.js applications.
Development Philosophy
- Write clean, maintainable, and scalable code
- Adhere to SOLID principles
- Favor functional and declarative programming patterns
- Emphasize type safety and component-driven approaches
Redux State Management
Core Principles
- Implement Redux Toolkit for global state management
- Use createSlice to define state, reducers, and actions together
- Normalize state structure to prevent deeply nested data
- Employ selectors to encapsulate state access
- Separate concerns by feature; avoid monolithic slices
Slice Structure
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
interface CounterState {
value: number
isLoading: boolean
}
const initialState: CounterState = {
value: 0,
isLoading: false,
}
const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment: (state) => {
state.value += 1
},
setLoading: (state, action: PayloadAction<boolean>) => {
state.isLoading = action.payload
},
},
})
export const { increment, setLoading } = counterSlice.actions
export default counterSlice.reducer
Naming Conventions
- PascalCase: Components, type definitions, interfaces
- kebab-case: Directory and file names
- camelCase: Variables, functions, methods, hooks, properties
- UPPERCASE: Environment variables, constants
Prefixes
- Event handlers:
handle (e.g., handleClick)
- Boolean variables: verbs (e.g.,
isLoading, hasError)
- Custom hooks:
use (e.g., useAuth)
TypeScript Integration
- Enable strict mode
- Define clear interfaces for props and Redux state structure
- Apply generics where type flexibility is needed
- Prefer interfaces over types for object structures
- Use typed hooks (
useAppDispatch, useAppSelector)
Async Operations
RTK Query
- Use RTK Query for data fetching and caching
- Define API slices with endpoints
- Leverage automatic cache invalidation
- Implement optimistic updates when appropriate
createAsyncThunk
export const fetchUser = createAsyncThunk(
'user/fetch',
async (userId: string, { rejectWithValue }) => {
try {
const response = await api.getUser(userId)
return response.data
} catch (error) {
return rejectWithValue(error.message)
}
}
)
Performance Optimization
- Use React.memo() strategically
- Implement useCallback for memoized functions
- Apply useMemo for expensive computations
- Avoid inline function definitions in JSX
- Use dynamic imports for code splitting
- Employ proper keys in lists (avoid index-based keys)
Selectors
- Create memoized selectors with createSelector
- Encapsulate state shape in selectors
- Compose selectors for derived data
- Avoid computing in components
Error Handling
- Implement error boundaries with external logging
- Use Zod for validation
- Handle async errors in thunks
- Provide user-friendly error messages
Testing
- Apply Jest and React Testing Library
- Follow Arrange-Act-Assert patterns
- Mock external dependencies
- Test reducers, selectors, and thunks independently
1---2name: redux-toolkit3description: Comprehensive Redux Toolkit best practices for React and Next.js applications with TypeScript.4---5
6# Redux Toolkit
7
8You are an expert in Redux Toolkit for state management in React and Next.js applications.
9
10## Development Philosophy
11
12- Write clean, maintainable, and scalable code
13- Adhere to SOLID principles
14- Favor functional and declarative programming patterns
15- Emphasize type safety and component-driven approaches
16
17## Redux State Management
18
19### Core Principles
20- Implement Redux Toolkit for global state management
21- Use createSlice to define state, reducers, and actions together
22- Normalize state structure to prevent deeply nested data
23- Employ selectors to encapsulate state access
24- Separate concerns by feature; avoid monolithic slices
25
26### Slice Structure
27```typescript
28import { createSlice, PayloadAction } from '@reduxjs/toolkit'
29
30interface CounterState {
31 value: number
32 isLoading: boolean
33}
34
35const initialState: CounterState = {
36 value: 0,
37 isLoading: false,
38}
39
40const counterSlice = createSlice({
41 name: 'counter',
42 initialState,
43 reducers: {
44 increment: (state) => {
45 state.value += 1
46 },
47 setLoading: (state, action: PayloadAction<boolean>) => {
48 state.isLoading = action.payload
49 },
50 },
51})
52
53export const { increment, setLoading } = counterSlice.actions
54export default counterSlice.reducer
55```
56
57## Naming Conventions
58
59- **PascalCase**: Components, type definitions, interfaces
60- **kebab-case**: Directory and file names
61- **camelCase**: Variables, functions, methods, hooks, properties
62- **UPPERCASE**: Environment variables, constants
63
64### Prefixes
65- Event handlers: `handle` (e.g., `handleClick`)
66- Boolean variables: verbs (e.g., `isLoading`, `hasError`)
67- Custom hooks: `use` (e.g., `useAuth`)
68
69## TypeScript Integration
70
71- Enable strict mode
72- Define clear interfaces for props and Redux state structure
73- Apply generics where type flexibility is needed
74- Prefer interfaces over types for object structures
75- Use typed hooks (`useAppDispatch`, `useAppSelector`)
76
77## Async Operations
78
79### RTK Query
80- Use RTK Query for data fetching and caching
81- Define API slices with endpoints
82- Leverage automatic cache invalidation
83- Implement optimistic updates when appropriate
84
85### createAsyncThunk
86```typescript
87export const fetchUser = createAsyncThunk(
88 'user/fetch',
89 async (userId: string, { rejectWithValue }) => {
90 try {
91 const response = await api.getUser(userId)
92 return response.data
93 } catch (error) {
94 return rejectWithValue(error.message)
95 }
96 }
97)
98```
99
100## Performance Optimization
101
102- Use React.memo() strategically
103- Implement useCallback for memoized functions
104- Apply useMemo for expensive computations
105- Avoid inline function definitions in JSX
106- Use dynamic imports for code splitting
107- Employ proper keys in lists (avoid index-based keys)
108
109## Selectors
110
111- Create memoized selectors with createSelector
112- Encapsulate state shape in selectors
113- Compose selectors for derived data
114- Avoid computing in components
115
116## Error Handling
117
118- Implement error boundaries with external logging
119- Use Zod for validation
120- Handle async errors in thunks
121- Provide user-friendly error messages
122
123## Testing
124
125- Apply Jest and React Testing Library
126- Follow Arrange-Act-Assert patterns
127- Mock external dependencies
128- Test reducers, selectors, and thunks independently