Skip to content

Commit 043aecd

Browse files
authored
chore: update cursor rules (#980)
1 parent 67bfe74 commit 043aecd

File tree

2 files changed

+182
-9
lines changed

2 files changed

+182
-9
lines changed

.cursorrules renamed to .cursor/rules/react-guidelines.mdc

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
---
2+
description:
3+
globs:
4+
alwaysApply: true
5+
---
16
# Expert Guidelines
27

38
You are an expert in TypeScript, Node.js, Next.js App Router, React, Shadcn UI, Radix UI and Tailwind.
49

5-
Code Style and Structure
10+
## Code Style and Structure
611

712
- Write concise, technical TypeScript code with accurate examples.
813
- Use functional and declarative programming patterns; avoid classes.
@@ -12,43 +17,43 @@ Code Style and Structure
1217
- Use console.log({value}) instead of console.log(value)
1318
- Use onCallback instead of handleCallback
1419

15-
Naming Conventions
20+
## Naming Conventions
1621

1722
- Use lowercase with dashes for directories (e.g., components/auth-wizard).
1823
- Favor named exports for components.
1924

20-
TypeScript Usage
25+
## TypeScript Usage
2126

2227
- Use TypeScript for all code; prefer interfaces over types.
2328
- Avoid enums; use maps instead.
2429
- Use functional components with TypeScript interfaces.
2530

26-
Syntax and Formatting
31+
## Syntax and Formatting
2732

2833
- Use the "function" keyword for pure functions.
2934
- Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
3035
- Use declarative JSX.
3136

32-
UI and Styling
37+
## UI and Styling
3338

3439
- Use Shadcn UI, Radix, and Tailwind for components and styling.
3540
- Implement responsive design with Tailwind CSS; use a mobile-first approach.
3641

37-
Performance Optimization
42+
## Performance Optimization
3843

3944
- Minimize 'use client', 'useEffect', and 'setState'; favor React Server Components (RSC).
4045
- Wrap client components in Suspense with fallback.
4146
- Use dynamic loading for non-critical components.
4247
- Optimize images: use WebP format, include size data, implement lazy loading.
4348

44-
Key Conventions
49+
## Key Conventions
4550

4651
- Optimize Web Vitals (LCP, CLS, FID).
4752
- Limit 'use client':
4853
- Favor server components and Next.js SSR.
4954
- Use only for Web API access in small components.
5055
- Avoid for data fetching or state management.
56+
- Follow Next.js docs for Data Fetching, Rendering, and Routing.
5157

52-
Follow Next.js docs for Data Fetching, Rendering, and Routing.
58+
Make sure not to start the dev server or run type of lint checking on agent mode.
5359

54-
---

.cursor/rules/react-patterns.mdc

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
---
2+
description:
3+
globs:
4+
alwaysApply: true
5+
---
6+
# React Patterns and Best Practices
7+
8+
## Core Philosophy
9+
10+
- **UIs are thin wrappers over data** - avoid using local state (like useState) unless absolutely necessary and it's independent of business logic
11+
- Even when local state seems needed, consider if you can flatten the UI state into a basic calculation
12+
- useState is only necessary if it's truly reactive and cannot be derived
13+
14+
## State Management
15+
16+
- **Choose state machines over multiple useStates** - multiple useState calls make code harder to reason about
17+
- Prefer a single state object with reducers for complex state logic
18+
- Co-locate related state rather than spreading it across multiple useState calls
19+
20+
## Component Architecture
21+
22+
- **Create new component abstractions when nesting conditional logic**
23+
- Move complex logic to new components rather than deeply nested conditionals
24+
- Use ternaries only for small, easily readable logic
25+
- Avoid top-level if/else statements in JSX - extract to components instead
26+
27+
## Side Effects and Dependencies
28+
29+
- **Avoid putting dependent logic in useEffects** - it causes misdirection about what the logic is doing
30+
- Choose to explicitly define logic rather than depend on implicit reactive behavior
31+
- When useEffect is necessary, be explicit about dependencies and cleanup
32+
- Prefer derived state and event handlers over effect-driven logic
33+
34+
## Timing and Async Patterns
35+
36+
- **setTimeouts are flaky and usually a hack** - always provide a comment explaining why setTimeout is needed
37+
- Consider alternatives like:
38+
- Proper loading states
39+
- Suspense boundaries
40+
- Event-driven patterns
41+
- State machines with delayed transitions
42+
- requestAnimateFrame and queuMicrotask
43+
44+
## Code Quality Impact
45+
46+
These patterns prevent subtle bugs that pile up into major issues. While code may "work" without following these guidelines, violations often lead to:
47+
- Hard-to-debug timing issues
48+
- Unexpected re-renders
49+
- State synchronization problems
50+
- Complex refactoring requirements
51+
52+
## Examples
53+
54+
### ❌ Avoid: Multiple useState
55+
```tsx
56+
const [loading, setLoading] = useState(false);
57+
const [error, setError] = useState(null);
58+
const [data, setData] = useState(null);
59+
```
60+
61+
### ✅ Prefer: State machine
62+
```tsx
63+
function useLazyRef<T>(fn: () => T) {
64+
const ref = React.useRef<T | null>(null);
65+
66+
if (ref.current === null) {
67+
ref.current = fn();
68+
}
69+
70+
return ref as React.RefObject<T>;
71+
}
72+
73+
interface Store<T> {
74+
subscribe: (callback: () => void) => () => void
75+
getState: () => T
76+
setState: <K extends keyof T>(key: K, value: T[K]) => void
77+
notify: () => void
78+
}
79+
80+
function createStore<T>(
81+
listenersRef: React.RefObject<Set<() => void>>,
82+
stateRef: React.RefObject<T>,
83+
onValueChange?: Partial<{
84+
[K in keyof T]: (value: T[K], store: Store<T>) => void
85+
}>
86+
): Store<T> {
87+
const store: Store<T> = {
88+
subscribe: (cb) => {
89+
listenersRef.current.add(cb);
90+
return () => listenersRef.current.delete(cb);
91+
},
92+
getState: () => stateRef.current,
93+
setState: (key, value) => {
94+
if (Object.is(stateRef.current[key], value)) return;
95+
stateRef.current[key] = value;
96+
onValueChange?.[key]?.(value, store);
97+
store.notify();
98+
},
99+
notify: () => {
100+
for (const cb of listenersRef.current) {
101+
cb();
102+
}
103+
},
104+
};
105+
106+
return store;
107+
}
108+
109+
function useStoreSelector<T, U>(
110+
store: Store<T>,
111+
selector: (state: T) => U
112+
): U {
113+
const getSnapshot = React.useCallback(
114+
() => selector(store.snapshot()),
115+
[store, selector]
116+
);
117+
118+
return React.useSyncExternalStore(
119+
store.subscribe,
120+
getSnapshot,
121+
getSnapshot
122+
);
123+
}
124+
```
125+
126+
### ❌ Avoid: Complex conditionals in JSX
127+
```tsx
128+
return (
129+
<div>
130+
{user ? (
131+
user.isAdmin ? (
132+
<AdminPanel />
133+
) : user.isPremium ? (
134+
<PremiumDashboard />
135+
) : (
136+
<BasicDashboard />
137+
)
138+
) : (
139+
<LoginForm />
140+
)}
141+
</div>
142+
);
143+
```
144+
145+
### ✅ Prefer: Component abstraction
146+
```tsx
147+
function UserDashboard({ user }) {
148+
if (!user) return <LoginForm />;
149+
if (user.isAdmin) return <AdminPanel />;
150+
if (user.isPremium) return <PremiumDashboard />;
151+
return <BasicDashboard />;
152+
}
153+
```
154+
155+
### ❌ Avoid: Effect-driven logic
156+
```tsx
157+
useEffect(() => {
158+
if (user && user.preferences) {
159+
setTheme(user.preferences.theme);
160+
}
161+
}, [user]);
162+
```
163+
164+
### ✅ Prefer: Derived values
165+
```tsx
166+
const theme = user?.preferences?.theme ?? 'default';
167+
```
168+

0 commit comments

Comments
 (0)