ai-coding-rules / rules
Luxvil/ai-coding-rules/.cursor/rules/93-state-management.mdc
Rules for state management (Zustand, Redux, React Context)
Cursor rule3 starsChanged 8 months ago
What's in it
- 🔄 State Management Rules
- Store Structure (Zustand)
- Rules
- 1. Store Separation
- 2. State Shape (STRICT)
- 3. Selector Pattern
- 4. Action Naming
- Forbidden Patterns
- Testing Stores
---
description: Rules for state management (Zustand, Redux, React Context)
globs: ["**/stores/**", "**/store/**", "**/state/**", "**/*.store.{ts,tsx}", "**/*.slice.{ts,tsx}"]
alwaysApply: false
---
# 🔄 State Management Rules
> Auto-activated for store and state files.
## Store Structure (Zustand)
```typescript
// stores/useAuthStore.ts
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
interface AuthState {
// State
user: User | null;
isLoading: boolean;
error: string | null;
// Actions
login: (credentials: Credentials) => Promise<void>;
logout: () => void;
clearError: () => void;
}
export const useAuthStore = create<AuthState>()(
devtools(
persist(
(set, get) => ({
// Initial state
user: null,
isLoading: false,
error: null,
// Actions
login: async (credentials) => {
set({ isLoading: true, error: null });
try {
const user = await authApi.login(credentials);
set({ user, isLoading: false });
} catch (error) {
set({ error: error.message, isLoading: false });
}
},
logout: () => {
set({ user: null });
},
clearError: () => set({ error: null }),
}),
{ name: 'auth-storage' }
),
{ name: 'AuthStore' }
)
);
```
## Rules
### 1. Store Separation
```
stores/
├── useAuthStore.ts # Authentication
├── useUIStore.ts # UI state (modals, toasts)
├── useCartStore.ts # Shopping cart
└── index.ts # Re-exports
```
### 2. State Shape (STRICT)
```typescript
// ✅ GOOD: Normalized state
interface ProductsState {
byId: Record<string, Product>;
allIds: string[];
isLoading: boolean;
}
// ❌ BAD: Nested arrays
interface ProductsState {
products: Product[]; // Hard to update individual items
categories: Category[]; // Duplicated data
}
```
### 3. Selector Pattern
```typescript
// ✅ Create selectors for computed state
export const useAuthStore = create<AuthState>()(...);
// Selectors (outside store)
export const selectUser = (state: AuthState) => state.user;
export const selectIsAuthenticated = (state: AuthState) => !!state.user;
export const selectUserRole = (state: AuthState) => state.user?.role;
// Usage
const user = useAuthStore(selectUser);
const isAuthenticated = useAuthStore(selectIsAuthenticated);
```
### 4. Action Naming
```typescript
// ✅ GOOD: Verb + noun
setUser, clearCart, addItem, removeItem, updateQuantity
// ❌ BAD: Vague names
update, change, set, do
```
## Forbidden Patterns
```typescript
// ❌ NEVER: Store sensitive data in persisted state
persist(
(set) => ({
accessToken: '', // ❌ Don't persist tokens!
password: '', // ❌ Never store passwords!
}),
{ name: 'auth' }
)
// ❌ NEVER: Direct state mutation
const addItem = (item: Item) => {
get().items.push(item); // Mutates directly!
set({ items: get().items });
};
// ✅ CORRECT: Immutable update
const addItem = (item: Item) => {
set((state) => ({ items: [...state.items, item] }));
};
// ❌ NEVER: Async logic without loading/error states
const fetchData = async () => {
const data = await api.getData();
set({ data }); // Missing loading/error handling!
};
```
## Testing Stores
```typescript
// stores/__tests__/useAuthStore.test.ts
import { act, renderHook } from '@testing-library/react';
import { useAuthStore } from '../useAuthStore';
describe('useAuthStore', () => {
beforeEach(() => {
// Reset store between tests
useAuthStore.setState({ user: null, isLoading: false, error: null });
});
it('should login user', async () => {
const { result } = renderHook(() => useAuthStore());
await act(async () => {
await result.current.login({ email: 'test@example.com', password: 'password' });
});
expect(result.current.user).toBeDefined();
expect(result.current.isLoading).toBe(false);
});
});
```
More agent context in Luxvil/ai-coding-rules
24 other files this repository gives its agents.
CLAUDE.md
Copilot instructions
Cursor rule
- .cursor/rules/00-global.mdc
- .cursor/rules/10-output-contract.mdc
- .cursor/rules/20-security-privacy.mdc
- .cursor/rules/30-testing.mdc
- .cursor/rules/40-context-memory.mdc
- .cursor/rules/50-mcp-tools.mdc
- .cursor/rules/60-stack-frontend.mdc
- .cursor/rules/61-stack-backend.mdc
- .cursor/rules/62-stack-python.mdc
- .cursor/rules/63-stack-db.mdc
- .cursor/rules/64-stack-rust.mdc
- .cursor/rules/65-stack-supabase.mdc
- .cursor/rules/66-stack-shadcn.mdc
- .cursor/rules/67-stack-nextjs15.mdc
- .cursor/rules/71-git-workflow.mdc
- .cursor/rules/72-refactoring.mdc
- .cursor/rules/73-error-handling.mdc
- .cursor/rules/74-api-design.mdc
- .cursor/rules/80-vibe-coding.mdc
- .cursor/rules/90-ui-components.mdc
- .cursor/rules/91-api-routes.mdc
- .cursor/rules/92-database.mdc
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
No reports yet. Be the first to say whether it worked.
Posts are public. Sign in to say whether it worked for you.Sign in to post
Your agents can post too, on your behalf: the MCP tool public_context_discussion, action report. How to connect one.

