{"owner":"sadmann7","repo":"tablecn","hasSkills":true,"totalSkillsCount":1,"totalTokensCount":3420,"categories":["cursor-rule"],"hasMcp":false,"mcpConfig":null,"found":[".cursor/rules/react-patterns.mdc"],"skills":{".cursor/rules/react-patterns.mdc":"---\ndescription: React patterns and best practices\nglobs: \nalwaysApply: true\n---\n\n# React Patterns\n\n## Code Style and Structure\n\n- Write concise, technical TypeScript code with accurate examples.\n- Use functional and declarative programming patterns; avoid classes.\n- Prefer iteration and modularization over code duplication.\n- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).\n- Structure files: exported component, subcomponents, helpers, static content, types.\n- Use console.log({ value }) instead of console.log(value)\n- Use onCallback instead of handleCallback\n- Use flex and gap instead of space-x-n and space-y-n\n- Use cn to compose class names\n- Just pass ref directly to the component because of react 19\n\n## Naming Conventions\n\n- Use lowercase with dashes for directories (e.g., components/auth-wizard).\n- Favor named exports for components.\n\n## TypeScript Usage\n\n- Use TypeScript for all code; prefer interfaces over types.\n- Avoid enums; use maps instead.\n- Use functional components with TypeScript interfaces.\n\n## Syntax and Formatting\n\n- Use the \"function\" keyword for pure functions.\n- Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.\n- Use declarative JSX.\n\n## UI and Styling\n\n- Use Shadcn UI, Base UI, Radix, and Tailwind for components and styling.\n- Implement responsive design with Tailwind CSS; use a mobile-first approach.\n\n## Performance Optimization\n\n- Minimize 'use client', 'useEffect', and 'setState'; favor React Server Components (RSC).\n- Wrap client components in Suspense with fallback.\n- Use dynamic loading for non-critical components.\n- Optimize images: use WebP format, include size data, implement lazy loading.\n\n## Key Conventions\n\n- Optimize Web Vitals (LCP, CLS, FID).\n- Limit 'use client':\n  - Favor server components and Next.js SSR.\n  - Use only for Web API access in small components.\n  - Avoid for data fetching or state management.\n- Follow Next.js docs for Data Fetching, Rendering, and Routing.\n\nMake sure not to start the dev server or run type of lint checking on agent mode.\n\n## React Patterns and Best Practices\n\n## Core Philosophy\n\n- **UIs are thin wrappers over data**: avoid using local state (like useState) unless absolutely necessary and it's independent of business logic\n- Even when local state seems needed, consider if you can flatten the UI state into a basic calculation\n- useState is only necessary if it's truly reactive and cannot be derived\n\n## State Management\n\n- **Choose state machines over multiple useStates**: multiple useState calls make code harder to reason about\n- Prefer a single state object with reducers for complex state logic\n- Co-locate related state rather than spreading it across multiple useState calls\n\n## Component Architecture\n\n- **Create new component abstractions when nesting conditional logic**\n- Move complex logic to new components rather than deeply nested conditionals\n- Use ternaries only for small, easily readable logic\n- Avoid top-level if/else statements in JSX; extract to components instead\n\n## Side Effects and Dependencies\n\n- **Avoid putting dependent logic in useEffects**: it causes misdirection about what the logic is doing\n- Choose to explicitly define logic rather than depend on implicit reactive behavior\n- When useEffect is necessary, be explicit about dependencies and cleanup\n- Prefer derived state and event handlers over effect-driven logic\n\n## Timing and Async Patterns\n\n- **setTimeouts are flaky and usually a hack**: always provide a comment explaining why setTimeout is needed\n- Consider alternatives like:\n  - Proper loading states\n  - Suspense boundaries\n  - Event-driven patterns\n  - State machines with delayed transitions\n  - requestAnimateFrame and queuMicrotask\n\n## Code Quality Impact\n\nThese patterns prevent subtle bugs that pile up into major issues. While code may \"work\" without following these guidelines, violations often lead to:\n\n- Hard-to-debug timing issues\n- Unexpected re-renders\n- State synchronization problems\n- Complex refactoring requirements\n\n## Examples\n\n### ❌ Avoid: Multiple useState\n\n```tsx\nconst [loading, setLoading] = useState(false);\nconst [error, setError] = useState(null);\nconst [data, setData] = useState(null);\n```\n\n### ✅ Prefer: State machine\n\n```tsx\nfunction useLazyRef<T>(fn: () => T) {\n  const ref = React.useRef<T | null>(null);\n\n  if (ref.current === null) {\n    ref.current = fn();\n  }\n\n  return ref as React.RefObject<T>;\n}\n\ninterface Store<T> {\n  subscribe: (callback: () => void) => () => void\n  getState: () => T\n  setState: <K extends keyof T>(key: K, value: T[K]) => void\n  notify: () => void\n}\n\nfunction createStore<T>(\n  listenersRef: React.RefObject<Set<() => void>>,\n  stateRef: React.RefObject<T>,\n  onValueChange?: Partial<{\n    [K in keyof T]: (value: T[K], store: Store<T>) => void\n  }>\n): Store<T> {\n  const store: Store<T> = {\n    subscribe: (cb) => {\n      listenersRef.current.add(cb);\n      return () => listenersRef.current.delete(cb);\n    },\n    getState: () => stateRef.current,\n    setState: (key, value) => {\n      if (Object.is(stateRef.current[key], value)) return;\n      stateRef.current[key] = value;\n      onValueChange?.[key]?.(value, store);\n      store.notify();\n    },\n    notify: () => {\n      for (const cb of listenersRef.current) {\n        cb();\n      }\n    },\n  };\n\n  return store;\n}\n\nfunction useStoreSelector<T, U>(\n  store: Store<T>,\n  selector: (state: T) => U\n): U {\n  return React.useSyncExternalStore(\n    store.subscribe,\n    () => selector(store.getState()),\n    () => selector(store.getState()),\n  );\n}\n```\n\n### ❌ Avoid: Complex conditionals in JSX\n\n```tsx\nreturn (\n  <div>\n    {user ? (\n      user.isAdmin ? (\n        <AdminPanel />\n      ) : user.isPremium ? (\n        <PremiumDashboard />\n      ) : (\n        <BasicDashboard />\n      )\n    ) : (\n      <LoginForm />\n    )}\n  </div>\n);\n```\n\n### ✅ Prefer: Component abstraction\n\n```tsx\nfunction UserDashboard({ user }) {\n  if (!user) return <LoginForm />;\n  if (user.isAdmin) return <AdminPanel />;\n  if (user.isPremium) return <PremiumDashboard />;\n  return <BasicDashboard />;\n}\n```\n\n### ❌ Avoid: Effect-driven logic\n\n```tsx\nuseEffect(() => {\n  if (user && user.preferences) {\n    setTheme(user.preferences.theme);\n  }\n}, [user]);\n```\n\n### ✅ Prefer: Derived values\n\n```tsx\nconst theme = user?.preferences?.theme ?? 'default';\n```\n\n## You Might Not Need an Effect\n\n> Reference: [You Might Not Need an Effect](https://react.dev/learn/you-might-not-need-an-effect)\n\nEffects are an escape hatch for synchronizing with **external systems** (non-React widgets, network, browser DOM). If there is no external system involved, you shouldn't need an Effect.\n\n### When to remove Effects\n\n- **Don't transform data for rendering in Effects**: calculate at the top level of your component; it re-runs automatically when props/state change\n- **Don't handle user events in Effects**: use the corresponding event handler where you know exactly what happened\n- **Don't update state based on props or state**: derive it during rendering instead of using Effect + setState (avoids extra render passes)\n- **Don't chain Effects** that each adjust state to trigger each other; calculate what you can during rendering and do the rest in event handlers\n- **Don't notify parent components about state changes via Effects**: call the parent's callback in the same event handler that updates state, so React batches both updates in one pass\n- **Don't pass data from child to parent via Effects**: lift the data fetching to the parent and pass it down as props\n\n### When Effects are appropriate\n\n- Synchronizing with external systems (jQuery widgets, browser APIs, network)\n- Analytics events that fire because the component was **displayed** (not because of a user action)\n- Data fetching (but always add cleanup to avoid race conditions, and prefer framework-level solutions)\n\n### Patterns to use instead of Effects\n\n| Instead of... | Do this |\n| --- | --- |\n| Effect + setState for derived values | `const fullName = firstName + ' ' + lastName;` |\n| Effect to cache expensive calculations | `const result = useMemo(() => expensiveFn(a, b), [a, b]);` |\n| Effect to reset state when a prop changes | Pass a `key` prop to force remounting |\n| Effect to adjust partial state on prop change | Store the selected **ID** instead of the selected **item**, and derive the item during render |\n| Effect to share logic between event handlers | Extract a plain function and call it from both handlers |\n| Effect to subscribe to an external store | Use `useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)` |\n\n### ❌ Avoid: Resetting state via Effect\n\n```tsx\nuseEffect(() => {\n  setComment('');\n}, [userId]);\n```\n\n### ✅ Prefer: Key-based reset\n\n```tsx\n<Profile userId={userId} key={userId} />\n```\n\n### ❌ Avoid: Storing derived state + syncing with Effect\n\n```tsx\nconst [visibleTodos, setVisibleTodos] = useState([]);\nuseEffect(() => {\n  setVisibleTodos(getFilteredTodos(todos, filter));\n}, [todos, filter]);\n```\n\n### ✅ Prefer: Calculate during rendering\n\n```tsx\nconst visibleTodos = getFilteredTodos(todos, filter);\n```\n\n### ❌ Avoid: Event-specific logic in an Effect\n\n```tsx\nuseEffect(() => {\n  if (product.isInCart) {\n    showNotification(`Added ${product.name} to the cart!`);\n  }\n}, [product]);\n```\n\n### ✅ Prefer: Logic in the event handler\n\n```tsx\nfunction onProductBuy() {\n  addToCart(product);\n  showNotification(`Added ${product.name} to the cart!`);\n}\n```\n\n### ❌ Avoid: Chained Effects\n\n```tsx\nuseEffect(() => { if (card?.gold) setGoldCardCount(c => c + 1); }, [card]);\nuseEffect(() => { if (goldCardCount > 3) { setRound(r => r + 1); setGoldCardCount(0); } }, [goldCardCount]);\nuseEffect(() => { if (round > 5) setIsGameOver(true); }, [round]);\n```\n\n### ✅ Prefer: Derive + compute in event handler\n\n```tsx\nconst isGameOver = round > 5;\n\nfunction onCardPlace(nextCard) {\n  setCard(nextCard);\n  if (nextCard.gold) {\n    if (goldCardCount < 3) setGoldCardCount(goldCardCount + 1);\n    else { setGoldCardCount(0); setRound(round + 1); }\n  }\n}\n```\n\n### Data fetching: always add cleanup\n\n```tsx\nuseEffect(() => {\n  let ignore = false;\n  fetchResults(query, page).then(json => {\n    if (!ignore) setResults(json);\n  });\n  return () => { ignore = true; };\n}, [query, page]);\n```\n\n## useMemo\n\n> Reference: [useMemo](https://react.dev/reference/react/useMemo)\n\n`useMemo` caches the **result** of a calculation between re-renders.\n\n### When to use useMemo\n\n- The calculation is **noticeably slow** (~1ms+ measured with `console.time`) and its dependencies rarely change\n- The result is passed as a prop to a `memo`-wrapped component (referential stability matters)\n- The value is used as a dependency of another Hook (useMemo, useCallback, useEffect)\n\n### When NOT to use useMemo\n\n- The calculation is cheap; just compute it inline\n- You're not passing the result to a memoized child or using it as a Hook dependency\n- A dependency changes on every render anyway (memoization is broken)\n\n### Prefer alternatives to useMemo\n\n1. **Accept JSX as children**: wrapper components that accept `children` let React skip re-rendering children when wrapper state updates\n2. **Keep state local**: don't lift transient state (forms, hover) higher than necessary\n3. **Keep rendering pure**: if re-rendering causes bugs, fix the bug instead of adding memoization\n4. **Remove unnecessary Effects** that update state, since chains of Effect-driven updates are the most common performance problem\n5. **Move objects/functions inside Effects** instead of memoizing them outside\n\n### ❌ Avoid: Effect + setState for derived computation\n\n```tsx\nconst [visibleTodos, setVisibleTodos] = useState([]);\nuseEffect(() => {\n  setVisibleTodos(getFilteredTodos(todos, filter));\n}, [todos, filter]);\n```\n\n### ✅ Prefer: Inline calculation (if cheap)\n\n```tsx\nconst visibleTodos = getFilteredTodos(todos, filter);\n```\n\n### ✅ Prefer: useMemo (if expensive)\n\n```tsx\nconst visibleTodos = useMemo(\n  () => getFilteredTodos(todos, filter),\n  [todos, filter]\n);\n```\n\n### ❌ Avoid: Object dependency that breaks memoization\n\n```tsx\nconst searchOptions = { matchMode: 'whole-word', text };\nconst visibleItems = useMemo(() => searchItems(allItems, searchOptions), [allItems, searchOptions]);\n```\n\n### ✅ Prefer: Move object inside useMemo\n\n```tsx\nconst visibleItems = useMemo(() => {\n  const searchOptions = { matchMode: 'whole-word', text };\n  return searchItems(allItems, searchOptions);\n}, [allItems, text]);\n```\n\n## useCallback\n\n> Reference: [useCallback](https://react.dev/reference/react/useCallback)\n\n`useCallback` caches the **function itself** between re-renders. It is equivalent to `useMemo(() => fn, deps)`.\n\n### When to use useCallback\n\n- Passing a function as a prop to a `memo`-wrapped component (so it can skip re-rendering)\n- The function is used as a dependency of another Hook (useEffect, useMemo, useCallback)\n- Writing a custom Hook that returns functions (always wrap returned functions in useCallback)\n\n### When NOT to use useCallback\n\n- The child component is not wrapped in `memo`; useCallback has no benefit\n- A dependency changes on every render anyway\n- The function is only used locally and not passed as a prop or Hook dependency\n\n### ❌ Avoid: useCallback without memo on the child\n\n```tsx\nfunction Parent() {\n  const onClick = useCallback(() => { /* ... */ }, []);\n  return <Child onClick={onClick} />; // Child is NOT memo-wrapped, useCallback is pointless\n}\n```\n\n### ✅ Prefer: useCallback paired with memo\n\n```tsx\nconst Child = memo(function Child({ onClick }) { /* ... */ });\n\nfunction Parent() {\n  const onClick = useCallback(() => { /* ... */ }, [dep]);\n  return <Child onClick={onClick} />;\n}\n```\n\n### ✅ Prefer: Move functions inside Effects instead of wrapping in useCallback\n\n```tsx\n// Instead of useCallback + function dependency in Effect:\nuseEffect(() => {\n  function createOptions() {\n    return { serverUrl: 'https://localhost:1234', roomId };\n  }\n  const connection = createConnection(createOptions());\n  connection.connect();\n  return () => connection.disconnect();\n}, [roomId]);\n```\n\n### Use updater functions to remove state dependencies\n\n```tsx\n// ❌ Depends on todos\nconst onTodoAdd = useCallback((text) => {\n  setTodos([...todos, { id: nextId++, text }]);\n}, [todos]);\n\n// ✅ No dependency on todos\nconst onTodoAdd = useCallback((text) => {\n  setTodos(todos => [...todos, { id: nextId++, text }]);\n}, []);\n```\n\n### Custom Hooks should wrap returned functions\n\n```tsx\nfunction useRouter() {\n  const { dispatch } = useContext(RouterStateContext);\n\n  const navigate = useCallback((url) => {\n    dispatch({ type: 'navigate', url });\n  }, [dispatch]);\n\n  return { navigate };\n}\n```\n"},"files":{".cursor/rules/react-patterns.mdc":"---\ndescription: React patterns and best practices\nglobs: \nalwaysApply: true\n---\n\n# React Patterns\n\n## Code Style and Structure\n\n- Write concise, technical TypeScript code with accurate examples.\n- Use functional and declarative programming patterns; avoid classes.\n- Prefer iteration and modularization over code duplication.\n- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).\n- Structure files: exported component, subcomponents, helpers, static content, types.\n- Use console.log({ value }) instead of console.log(value)\n- Use onCallback instead of handleCallback\n- Use flex and gap instead of space-x-n and space-y-n\n- Use cn to compose class names\n- Just pass ref directly to the component because of react 19\n\n## Naming Conventions\n\n- Use lowercase with dashes for directories (e.g., components/auth-wizard).\n- Favor named exports for components.\n\n## TypeScript Usage\n\n- Use TypeScript for all code; prefer interfaces over types.\n- Avoid enums; use maps instead.\n- Use functional components with TypeScript interfaces.\n\n## Syntax and Formatting\n\n- Use the \"function\" keyword for pure functions.\n- Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.\n- Use declarative JSX.\n\n## UI and Styling\n\n- Use Shadcn UI, Base UI, Radix, and Tailwind for components and styling.\n- Implement responsive design with Tailwind CSS; use a mobile-first approach.\n\n## Performance Optimization\n\n- Minimize 'use client', 'useEffect', and 'setState'; favor React Server Components (RSC).\n- Wrap client components in Suspense with fallback.\n- Use dynamic loading for non-critical components.\n- Optimize images: use WebP format, include size data, implement lazy loading.\n\n## Key Conventions\n\n- Optimize Web Vitals (LCP, CLS, FID).\n- Limit 'use client':\n  - Favor server components and Next.js SSR.\n  - Use only for Web API access in small components.\n  - Avoid for data fetching or state management.\n- Follow Next.js docs for Data Fetching, Rendering, and Routing.\n\nMake sure not to start the dev server or run type of lint checking on agent mode.\n\n## React Patterns and Best Practices\n\n## Core Philosophy\n\n- **UIs are thin wrappers over data**: avoid using local state (like useState) unless absolutely necessary and it's independent of business logic\n- Even when local state seems needed, consider if you can flatten the UI state into a basic calculation\n- useState is only necessary if it's truly reactive and cannot be derived\n\n## State Management\n\n- **Choose state machines over multiple useStates**: multiple useState calls make code harder to reason about\n- Prefer a single state object with reducers for complex state logic\n- Co-locate related state rather than spreading it across multiple useState calls\n\n## Component Architecture\n\n- **Create new component abstractions when nesting conditional logic**\n- Move complex logic to new components rather than deeply nested conditionals\n- Use ternaries only for small, easily readable logic\n- Avoid top-level if/else statements in JSX; extract to components instead\n\n## Side Effects and Dependencies\n\n- **Avoid putting dependent logic in useEffects**: it causes misdirection about what the logic is doing\n- Choose to explicitly define logic rather than depend on implicit reactive behavior\n- When useEffect is necessary, be explicit about dependencies and cleanup\n- Prefer derived state and event handlers over effect-driven logic\n\n## Timing and Async Patterns\n\n- **setTimeouts are flaky and usually a hack**: always provide a comment explaining why setTimeout is needed\n- Consider alternatives like:\n  - Proper loading states\n  - Suspense boundaries\n  - Event-driven patterns\n  - State machines with delayed transitions\n  - requestAnimateFrame and queuMicrotask\n\n## Code Quality Impact\n\nThese patterns prevent subtle bugs that pile up into major issues. While code may \"work\" without following these guidelines, violations often lead to:\n\n- Hard-to-debug timing issues\n- Unexpected re-renders\n- State synchronization problems\n- Complex refactoring requirements\n\n## Examples\n\n### ❌ Avoid: Multiple useState\n\n```tsx\nconst [loading, setLoading] = useState(false);\nconst [error, setError] = useState(null);\nconst [data, setData] = useState(null);\n```\n\n### ✅ Prefer: State machine\n\n```tsx\nfunction useLazyRef<T>(fn: () => T) {\n  const ref = React.useRef<T | null>(null);\n\n  if (ref.current === null) {\n    ref.current = fn();\n  }\n\n  return ref as React.RefObject<T>;\n}\n\ninterface Store<T> {\n  subscribe: (callback: () => void) => () => void\n  getState: () => T\n  setState: <K extends keyof T>(key: K, value: T[K]) => void\n  notify: () => void\n}\n\nfunction createStore<T>(\n  listenersRef: React.RefObject<Set<() => void>>,\n  stateRef: React.RefObject<T>,\n  onValueChange?: Partial<{\n    [K in keyof T]: (value: T[K], store: Store<T>) => void\n  }>\n): Store<T> {\n  const store: Store<T> = {\n    subscribe: (cb) => {\n      listenersRef.current.add(cb);\n      return () => listenersRef.current.delete(cb);\n    },\n    getState: () => stateRef.current,\n    setState: (key, value) => {\n      if (Object.is(stateRef.current[key], value)) return;\n      stateRef.current[key] = value;\n      onValueChange?.[key]?.(value, store);\n      store.notify();\n    },\n    notify: () => {\n      for (const cb of listenersRef.current) {\n        cb();\n      }\n    },\n  };\n\n  return store;\n}\n\nfunction useStoreSelector<T, U>(\n  store: Store<T>,\n  selector: (state: T) => U\n): U {\n  return React.useSyncExternalStore(\n    store.subscribe,\n    () => selector(store.getState()),\n    () => selector(store.getState()),\n  );\n}\n```\n\n### ❌ Avoid: Complex conditionals in JSX\n\n```tsx\nreturn (\n  <div>\n    {user ? (\n      user.isAdmin ? (\n        <AdminPanel />\n      ) : user.isPremium ? (\n        <PremiumDashboard />\n      ) : (\n        <BasicDashboard />\n      )\n    ) : (\n      <LoginForm />\n    )}\n  </div>\n);\n```\n\n### ✅ Prefer: Component abstraction\n\n```tsx\nfunction UserDashboard({ user }) {\n  if (!user) return <LoginForm />;\n  if (user.isAdmin) return <AdminPanel />;\n  if (user.isPremium) return <PremiumDashboard />;\n  return <BasicDashboard />;\n}\n```\n\n### ❌ Avoid: Effect-driven logic\n\n```tsx\nuseEffect(() => {\n  if (user && user.preferences) {\n    setTheme(user.preferences.theme);\n  }\n}, [user]);\n```\n\n### ✅ Prefer: Derived values\n\n```tsx\nconst theme = user?.preferences?.theme ?? 'default';\n```\n\n## You Might Not Need an Effect\n\n> Reference: [You Might Not Need an Effect](https://react.dev/learn/you-might-not-need-an-effect)\n\nEffects are an escape hatch for synchronizing with **external systems** (non-React widgets, network, browser DOM). If there is no external system involved, you shouldn't need an Effect.\n\n### When to remove Effects\n\n- **Don't transform data for rendering in Effects**: calculate at the top level of your component; it re-runs automatically when props/state change\n- **Don't handle user events in Effects**: use the corresponding event handler where you know exactly what happened\n- **Don't update state based on props or state**: derive it during rendering instead of using Effect + setState (avoids extra render passes)\n- **Don't chain Effects** that each adjust state to trigger each other; calculate what you can during rendering and do the rest in event handlers\n- **Don't notify parent components about state changes via Effects**: call the parent's callback in the same event handler that updates state, so React batches both updates in one pass\n- **Don't pass data from child to parent via Effects**: lift the data fetching to the parent and pass it down as props\n\n### When Effects are appropriate\n\n- Synchronizing with external systems (jQuery widgets, browser APIs, network)\n- Analytics events that fire because the component was **displayed** (not because of a user action)\n- Data fetching (but always add cleanup to avoid race conditions, and prefer framework-level solutions)\n\n### Patterns to use instead of Effects\n\n| Instead of... | Do this |\n| --- | --- |\n| Effect + setState for derived values | `const fullName = firstName + ' ' + lastName;` |\n| Effect to cache expensive calculations | `const result = useMemo(() => expensiveFn(a, b), [a, b]);` |\n| Effect to reset state when a prop changes | Pass a `key` prop to force remounting |\n| Effect to adjust partial state on prop change | Store the selected **ID** instead of the selected **item**, and derive the item during render |\n| Effect to share logic between event handlers | Extract a plain function and call it from both handlers |\n| Effect to subscribe to an external store | Use `useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)` |\n\n### ❌ Avoid: Resetting state via Effect\n\n```tsx\nuseEffect(() => {\n  setComment('');\n}, [userId]);\n```\n\n### ✅ Prefer: Key-based reset\n\n```tsx\n<Profile userId={userId} key={userId} />\n```\n\n### ❌ Avoid: Storing derived state + syncing with Effect\n\n```tsx\nconst [visibleTodos, setVisibleTodos] = useState([]);\nuseEffect(() => {\n  setVisibleTodos(getFilteredTodos(todos, filter));\n}, [todos, filter]);\n```\n\n### ✅ Prefer: Calculate during rendering\n\n```tsx\nconst visibleTodos = getFilteredTodos(todos, filter);\n```\n\n### ❌ Avoid: Event-specific logic in an Effect\n\n```tsx\nuseEffect(() => {\n  if (product.isInCart) {\n    showNotification(`Added ${product.name} to the cart!`);\n  }\n}, [product]);\n```\n\n### ✅ Prefer: Logic in the event handler\n\n```tsx\nfunction onProductBuy() {\n  addToCart(product);\n  showNotification(`Added ${product.name} to the cart!`);\n}\n```\n\n### ❌ Avoid: Chained Effects\n\n```tsx\nuseEffect(() => { if (card?.gold) setGoldCardCount(c => c + 1); }, [card]);\nuseEffect(() => { if (goldCardCount > 3) { setRound(r => r + 1); setGoldCardCount(0); } }, [goldCardCount]);\nuseEffect(() => { if (round > 5) setIsGameOver(true); }, [round]);\n```\n\n### ✅ Prefer: Derive + compute in event handler\n\n```tsx\nconst isGameOver = round > 5;\n\nfunction onCardPlace(nextCard) {\n  setCard(nextCard);\n  if (nextCard.gold) {\n    if (goldCardCount < 3) setGoldCardCount(goldCardCount + 1);\n    else { setGoldCardCount(0); setRound(round + 1); }\n  }\n}\n```\n\n### Data fetching: always add cleanup\n\n```tsx\nuseEffect(() => {\n  let ignore = false;\n  fetchResults(query, page).then(json => {\n    if (!ignore) setResults(json);\n  });\n  return () => { ignore = true; };\n}, [query, page]);\n```\n\n## useMemo\n\n> Reference: [useMemo](https://react.dev/reference/react/useMemo)\n\n`useMemo` caches the **result** of a calculation between re-renders.\n\n### When to use useMemo\n\n- The calculation is **noticeably slow** (~1ms+ measured with `console.time`) and its dependencies rarely change\n- The result is passed as a prop to a `memo`-wrapped component (referential stability matters)\n- The value is used as a dependency of another Hook (useMemo, useCallback, useEffect)\n\n### When NOT to use useMemo\n\n- The calculation is cheap; just compute it inline\n- You're not passing the result to a memoized child or using it as a Hook dependency\n- A dependency changes on every render anyway (memoization is broken)\n\n### Prefer alternatives to useMemo\n\n1. **Accept JSX as children**: wrapper components that accept `children` let React skip re-rendering children when wrapper state updates\n2. **Keep state local**: don't lift transient state (forms, hover) higher than necessary\n3. **Keep rendering pure**: if re-rendering causes bugs, fix the bug instead of adding memoization\n4. **Remove unnecessary Effects** that update state, since chains of Effect-driven updates are the most common performance problem\n5. **Move objects/functions inside Effects** instead of memoizing them outside\n\n### ❌ Avoid: Effect + setState for derived computation\n\n```tsx\nconst [visibleTodos, setVisibleTodos] = useState([]);\nuseEffect(() => {\n  setVisibleTodos(getFilteredTodos(todos, filter));\n}, [todos, filter]);\n```\n\n### ✅ Prefer: Inline calculation (if cheap)\n\n```tsx\nconst visibleTodos = getFilteredTodos(todos, filter);\n```\n\n### ✅ Prefer: useMemo (if expensive)\n\n```tsx\nconst visibleTodos = useMemo(\n  () => getFilteredTodos(todos, filter),\n  [todos, filter]\n);\n```\n\n### ❌ Avoid: Object dependency that breaks memoization\n\n```tsx\nconst searchOptions = { matchMode: 'whole-word', text };\nconst visibleItems = useMemo(() => searchItems(allItems, searchOptions), [allItems, searchOptions]);\n```\n\n### ✅ Prefer: Move object inside useMemo\n\n```tsx\nconst visibleItems = useMemo(() => {\n  const searchOptions = { matchMode: 'whole-word', text };\n  return searchItems(allItems, searchOptions);\n}, [allItems, text]);\n```\n\n## useCallback\n\n> Reference: [useCallback](https://react.dev/reference/react/useCallback)\n\n`useCallback` caches the **function itself** between re-renders. It is equivalent to `useMemo(() => fn, deps)`.\n\n### When to use useCallback\n\n- Passing a function as a prop to a `memo`-wrapped component (so it can skip re-rendering)\n- The function is used as a dependency of another Hook (useEffect, useMemo, useCallback)\n- Writing a custom Hook that returns functions (always wrap returned functions in useCallback)\n\n### When NOT to use useCallback\n\n- The child component is not wrapped in `memo`; useCallback has no benefit\n- A dependency changes on every render anyway\n- The function is only used locally and not passed as a prop or Hook dependency\n\n### ❌ Avoid: useCallback without memo on the child\n\n```tsx\nfunction Parent() {\n  const onClick = useCallback(() => { /* ... */ }, []);\n  return <Child onClick={onClick} />; // Child is NOT memo-wrapped, useCallback is pointless\n}\n```\n\n### ✅ Prefer: useCallback paired with memo\n\n```tsx\nconst Child = memo(function Child({ onClick }) { /* ... */ });\n\nfunction Parent() {\n  const onClick = useCallback(() => { /* ... */ }, [dep]);\n  return <Child onClick={onClick} />;\n}\n```\n\n### ✅ Prefer: Move functions inside Effects instead of wrapping in useCallback\n\n```tsx\n// Instead of useCallback + function dependency in Effect:\nuseEffect(() => {\n  function createOptions() {\n    return { serverUrl: 'https://localhost:1234', roomId };\n  }\n  const connection = createConnection(createOptions());\n  connection.connect();\n  return () => connection.disconnect();\n}, [roomId]);\n```\n\n### Use updater functions to remove state dependencies\n\n```tsx\n// ❌ Depends on todos\nconst onTodoAdd = useCallback((text) => {\n  setTodos([...todos, { id: nextId++, text }]);\n}, [todos]);\n\n// ✅ No dependency on todos\nconst onTodoAdd = useCallback((text) => {\n  setTodos(todos => [...todos, { id: nextId++, text }]);\n}, []);\n```\n\n### Custom Hooks should wrap returned functions\n\n```tsx\nfunction useRouter() {\n  const { dispatch } = useContext(RouterStateContext);\n\n  const navigate = useCallback((url) => {\n    dispatch({ type: 'navigate', url });\n  }, [dispatch]);\n\n  return { navigate };\n}\n```\n"},"items":[{"name":"react-patterns.mdc","path":".cursor/rules/react-patterns.mdc","rawUrl":"https://raw.githubusercontent.com/sadmann7/tablecn/HEAD/.cursor/rules/react-patterns.mdc","title":"Cursor Rule: react-patterns","category":"cursor-rule","format":"mdc","content":"---\ndescription: React patterns and best practices\nglobs: \nalwaysApply: true\n---\n\n# React Patterns\n\n## Code Style and Structure\n\n- Write concise, technical TypeScript code with accurate examples.\n- Use functional and declarative programming patterns; avoid classes.\n- Prefer iteration and modularization over code duplication.\n- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).\n- Structure files: exported component, subcomponents, helpers, static content, types.\n- Use console.log({ value }) instead of console.log(value)\n- Use onCallback instead of handleCallback\n- Use flex and gap instead of space-x-n and space-y-n\n- Use cn to compose class names\n- Just pass ref directly to the component because of react 19\n\n## Naming Conventions\n\n- Use lowercase with dashes for directories (e.g., components/auth-wizard).\n- Favor named exports for components.\n\n## TypeScript Usage\n\n- Use TypeScript for all code; prefer interfaces over types.\n- Avoid enums; use maps instead.\n- Use functional components with TypeScript interfaces.\n\n## Syntax and Formatting\n\n- Use the \"function\" keyword for pure functions.\n- Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.\n- Use declarative JSX.\n\n## UI and Styling\n\n- Use Shadcn UI, Base UI, Radix, and Tailwind for components and styling.\n- Implement responsive design with Tailwind CSS; use a mobile-first approach.\n\n## Performance Optimization\n\n- Minimize 'use client', 'useEffect', and 'setState'; favor React Server Components (RSC).\n- Wrap client components in Suspense with fallback.\n- Use dynamic loading for non-critical components.\n- Optimize images: use WebP format, include size data, implement lazy loading.\n\n## Key Conventions\n\n- Optimize Web Vitals (LCP, CLS, FID).\n- Limit 'use client':\n  - Favor server components and Next.js SSR.\n  - Use only for Web API access in small components.\n  - Avoid for data fetching or state management.\n- Follow Next.js docs for Data Fetching, Rendering, and Routing.\n\nMake sure not to start the dev server or run type of lint checking on agent mode.\n\n## React Patterns and Best Practices\n\n## Core Philosophy\n\n- **UIs are thin wrappers over data**: avoid using local state (like useState) unless absolutely necessary and it's independent of business logic\n- Even when local state seems needed, consider if you can flatten the UI state into a basic calculation\n- useState is only necessary if it's truly reactive and cannot be derived\n\n## State Management\n\n- **Choose state machines over multiple useStates**: multiple useState calls make code harder to reason about\n- Prefer a single state object with reducers for complex state logic\n- Co-locate related state rather than spreading it across multiple useState calls\n\n## Component Architecture\n\n- **Create new component abstractions when nesting conditional logic**\n- Move complex logic to new components rather than deeply nested conditionals\n- Use ternaries only for small, easily readable logic\n- Avoid top-level if/else statements in JSX; extract to components instead\n\n## Side Effects and Dependencies\n\n- **Avoid putting dependent logic in useEffects**: it causes misdirection about what the logic is doing\n- Choose to explicitly define logic rather than depend on implicit reactive behavior\n- When useEffect is necessary, be explicit about dependencies and cleanup\n- Prefer derived state and event handlers over effect-driven logic\n\n## Timing and Async Patterns\n\n- **setTimeouts are flaky and usually a hack**: always provide a comment explaining why setTimeout is needed\n- Consider alternatives like:\n  - Proper loading states\n  - Suspense boundaries\n  - Event-driven patterns\n  - State machines with delayed transitions\n  - requestAnimateFrame and queuMicrotask\n\n## Code Quality Impact\n\nThese patterns prevent subtle bugs that pile up into major issues. While code may \"work\" without following these guidelines, violations often lead to:\n\n- Hard-to-debug timing issues\n- Unexpected re-renders\n- State synchronization problems\n- Complex refactoring requirements\n\n## Examples\n\n### ❌ Avoid: Multiple useState\n\n```tsx\nconst [loading, setLoading] = useState(false);\nconst [error, setError] = useState(null);\nconst [data, setData] = useState(null);\n```\n\n### ✅ Prefer: State machine\n\n```tsx\nfunction useLazyRef<T>(fn: () => T) {\n  const ref = React.useRef<T | null>(null);\n\n  if (ref.current === null) {\n    ref.current = fn();\n  }\n\n  return ref as React.RefObject<T>;\n}\n\ninterface Store<T> {\n  subscribe: (callback: () => void) => () => void\n  getState: () => T\n  setState: <K extends keyof T>(key: K, value: T[K]) => void\n  notify: () => void\n}\n\nfunction createStore<T>(\n  listenersRef: React.RefObject<Set<() => void>>,\n  stateRef: React.RefObject<T>,\n  onValueChange?: Partial<{\n    [K in keyof T]: (value: T[K], store: Store<T>) => void\n  }>\n): Store<T> {\n  const store: Store<T> = {\n    subscribe: (cb) => {\n      listenersRef.current.add(cb);\n      return () => listenersRef.current.delete(cb);\n    },\n    getState: () => stateRef.current,\n    setState: (key, value) => {\n      if (Object.is(stateRef.current[key], value)) return;\n      stateRef.current[key] = value;\n      onValueChange?.[key]?.(value, store);\n      store.notify();\n    },\n    notify: () => {\n      for (const cb of listenersRef.current) {\n        cb();\n      }\n    },\n  };\n\n  return store;\n}\n\nfunction useStoreSelector<T, U>(\n  store: Store<T>,\n  selector: (state: T) => U\n): U {\n  return React.useSyncExternalStore(\n    store.subscribe,\n    () => selector(store.getState()),\n    () => selector(store.getState()),\n  );\n}\n```\n\n### ❌ Avoid: Complex conditionals in JSX\n\n```tsx\nreturn (\n  <div>\n    {user ? (\n      user.isAdmin ? (\n        <AdminPanel />\n      ) : user.isPremium ? (\n        <PremiumDashboard />\n      ) : (\n        <BasicDashboard />\n      )\n    ) : (\n      <LoginForm />\n    )}\n  </div>\n);\n```\n\n### ✅ Prefer: Component abstraction\n\n```tsx\nfunction UserDashboard({ user }) {\n  if (!user) return <LoginForm />;\n  if (user.isAdmin) return <AdminPanel />;\n  if (user.isPremium) return <PremiumDashboard />;\n  return <BasicDashboard />;\n}\n```\n\n### ❌ Avoid: Effect-driven logic\n\n```tsx\nuseEffect(() => {\n  if (user && user.preferences) {\n    setTheme(user.preferences.theme);\n  }\n}, [user]);\n```\n\n### ✅ Prefer: Derived values\n\n```tsx\nconst theme = user?.preferences?.theme ?? 'default';\n```\n\n## You Might Not Need an Effect\n\n> Reference: [You Might Not Need an Effect](https://react.dev/learn/you-might-not-need-an-effect)\n\nEffects are an escape hatch for synchronizing with **external systems** (non-React widgets, network, browser DOM). If there is no external system involved, you shouldn't need an Effect.\n\n### When to remove Effects\n\n- **Don't transform data for rendering in Effects**: calculate at the top level of your component; it re-runs automatically when props/state change\n- **Don't handle user events in Effects**: use the corresponding event handler where you know exactly what happened\n- **Don't update state based on props or state**: derive it during rendering instead of using Effect + setState (avoids extra render passes)\n- **Don't chain Effects** that each adjust state to trigger each other; calculate what you can during rendering and do the rest in event handlers\n- **Don't notify parent components about state changes via Effects**: call the parent's callback in the same event handler that updates state, so React batches both updates in one pass\n- **Don't pass data from child to parent via Effects**: lift the data fetching to the parent and pass it down as props\n\n### When Effects are appropriate\n\n- Synchronizing with external systems (jQuery widgets, browser APIs, network)\n- Analytics events that fire because the component was **displayed** (not because of a user action)\n- Data fetching (but always add cleanup to avoid race conditions, and prefer framework-level solutions)\n\n### Patterns to use instead of Effects\n\n| Instead of... | Do this |\n| --- | --- |\n| Effect + setState for derived values | `const fullName = firstName + ' ' + lastName;` |\n| Effect to cache expensive calculations | `const result = useMemo(() => expensiveFn(a, b), [a, b]);` |\n| Effect to reset state when a prop changes | Pass a `key` prop to force remounting |\n| Effect to adjust partial state on prop change | Store the selected **ID** instead of the selected **item**, and derive the item during render |\n| Effect to share logic between event handlers | Extract a plain function and call it from both handlers |\n| Effect to subscribe to an external store | Use `useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)` |\n\n### ❌ Avoid: Resetting state via Effect\n\n```tsx\nuseEffect(() => {\n  setComment('');\n}, [userId]);\n```\n\n### ✅ Prefer: Key-based reset\n\n```tsx\n<Profile userId={userId} key={userId} />\n```\n\n### ❌ Avoid: Storing derived state + syncing with Effect\n\n```tsx\nconst [visibleTodos, setVisibleTodos] = useState([]);\nuseEffect(() => {\n  setVisibleTodos(getFilteredTodos(todos, filter));\n}, [todos, filter]);\n```\n\n### ✅ Prefer: Calculate during rendering\n\n```tsx\nconst visibleTodos = getFilteredTodos(todos, filter);\n```\n\n### ❌ Avoid: Event-specific logic in an Effect\n\n```tsx\nuseEffect(() => {\n  if (product.isInCart) {\n    showNotification(`Added ${product.name} to the cart!`);\n  }\n}, [product]);\n```\n\n### ✅ Prefer: Logic in the event handler\n\n```tsx\nfunction onProductBuy() {\n  addToCart(product);\n  showNotification(`Added ${product.name} to the cart!`);\n}\n```\n\n### ❌ Avoid: Chained Effects\n\n```tsx\nuseEffect(() => { if (card?.gold) setGoldCardCount(c => c + 1); }, [card]);\nuseEffect(() => { if (goldCardCount > 3) { setRound(r => r + 1); setGoldCardCount(0); } }, [goldCardCount]);\nuseEffect(() => { if (round > 5) setIsGameOver(true); }, [round]);\n```\n\n### ✅ Prefer: Derive + compute in event handler\n\n```tsx\nconst isGameOver = round > 5;\n\nfunction onCardPlace(nextCard) {\n  setCard(nextCard);\n  if (nextCard.gold) {\n    if (goldCardCount < 3) setGoldCardCount(goldCardCount + 1);\n    else { setGoldCardCount(0); setRound(round + 1); }\n  }\n}\n```\n\n### Data fetching: always add cleanup\n\n```tsx\nuseEffect(() => {\n  let ignore = false;\n  fetchResults(query, page).then(json => {\n    if (!ignore) setResults(json);\n  });\n  return () => { ignore = true; };\n}, [query, page]);\n```\n\n## useMemo\n\n> Reference: [useMemo](https://react.dev/reference/react/useMemo)\n\n`useMemo` caches the **result** of a calculation between re-renders.\n\n### When to use useMemo\n\n- The calculation is **noticeably slow** (~1ms+ measured with `console.time`) and its dependencies rarely change\n- The result is passed as a prop to a `memo`-wrapped component (referential stability matters)\n- The value is used as a dependency of another Hook (useMemo, useCallback, useEffect)\n\n### When NOT to use useMemo\n\n- The calculation is cheap; just compute it inline\n- You're not passing the result to a memoized child or using it as a Hook dependency\n- A dependency changes on every render anyway (memoization is broken)\n\n### Prefer alternatives to useMemo\n\n1. **Accept JSX as children**: wrapper components that accept `children` let React skip re-rendering children when wrapper state updates\n2. **Keep state local**: don't lift transient state (forms, hover) higher than necessary\n3. **Keep rendering pure**: if re-rendering causes bugs, fix the bug instead of adding memoization\n4. **Remove unnecessary Effects** that update state, since chains of Effect-driven updates are the most common performance problem\n5. **Move objects/functions inside Effects** instead of memoizing them outside\n\n### ❌ Avoid: Effect + setState for derived computation\n\n```tsx\nconst [visibleTodos, setVisibleTodos] = useState([]);\nuseEffect(() => {\n  setVisibleTodos(getFilteredTodos(todos, filter));\n}, [todos, filter]);\n```\n\n### ✅ Prefer: Inline calculation (if cheap)\n\n```tsx\nconst visibleTodos = getFilteredTodos(todos, filter);\n```\n\n### ✅ Prefer: useMemo (if expensive)\n\n```tsx\nconst visibleTodos = useMemo(\n  () => getFilteredTodos(todos, filter),\n  [todos, filter]\n);\n```\n\n### ❌ Avoid: Object dependency that breaks memoization\n\n```tsx\nconst searchOptions = { matchMode: 'whole-word', text };\nconst visibleItems = useMemo(() => searchItems(allItems, searchOptions), [allItems, searchOptions]);\n```\n\n### ✅ Prefer: Move object inside useMemo\n\n```tsx\nconst visibleItems = useMemo(() => {\n  const searchOptions = { matchMode: 'whole-word', text };\n  return searchItems(allItems, searchOptions);\n}, [allItems, text]);\n```\n\n## useCallback\n\n> Reference: [useCallback](https://react.dev/reference/react/useCallback)\n\n`useCallback` caches the **function itself** between re-renders. It is equivalent to `useMemo(() => fn, deps)`.\n\n### When to use useCallback\n\n- Passing a function as a prop to a `memo`-wrapped component (so it can skip re-rendering)\n- The function is used as a dependency of another Hook (useEffect, useMemo, useCallback)\n- Writing a custom Hook that returns functions (always wrap returned functions in useCallback)\n\n### When NOT to use useCallback\n\n- The child component is not wrapped in `memo`; useCallback has no benefit\n- A dependency changes on every render anyway\n- The function is only used locally and not passed as a prop or Hook dependency\n\n### ❌ Avoid: useCallback without memo on the child\n\n```tsx\nfunction Parent() {\n  const onClick = useCallback(() => { /* ... */ }, []);\n  return <Child onClick={onClick} />; // Child is NOT memo-wrapped, useCallback is pointless\n}\n```\n\n### ✅ Prefer: useCallback paired with memo\n\n```tsx\nconst Child = memo(function Child({ onClick }) { /* ... */ });\n\nfunction Parent() {\n  const onClick = useCallback(() => { /* ... */ }, [dep]);\n  return <Child onClick={onClick} />;\n}\n```\n\n### ✅ Prefer: Move functions inside Effects instead of wrapping in useCallback\n\n```tsx\n// Instead of useCallback + function dependency in Effect:\nuseEffect(() => {\n  function createOptions() {\n    return { serverUrl: 'https://localhost:1234', roomId };\n  }\n  const connection = createConnection(createOptions());\n  connection.connect();\n  return () => connection.disconnect();\n}, [roomId]);\n```\n\n### Use updater functions to remove state dependencies\n\n```tsx\n// ❌ Depends on todos\nconst onTodoAdd = useCallback((text) => {\n  setTodos([...todos, { id: nextId++, text }]);\n}, [todos]);\n\n// ✅ No dependency on todos\nconst onTodoAdd = useCallback((text) => {\n  setTodos(todos => [...todos, { id: nextId++, text }]);\n}, []);\n```\n\n### Custom Hooks should wrap returned functions\n\n```tsx\nfunction useRouter() {\n  const { dispatch } = useContext(RouterStateContext);\n\n  const navigate = useCallback((url) => {\n    dispatch({ type: 'navigate', url });\n  }, [dispatch]);\n\n  return { navigate };\n}\n```\n","frontmatter":{"description":"React patterns and best practices","globs":null,"alwaysApply":true},"isInternal":false,"tokens":3420,"sizeBytes":14747}],"systemPromptSnippet":"<yakaai_skills repo=\"sadmann7/tablecn\">\n<!-- File: .cursor/rules/react-patterns.mdc (Tokens: ~3420 | Category: cursor-rule) -->\n---\ndescription: React patterns and best practices\nglobs: \nalwaysApply: true\n---\n\n# React Patterns\n\n## Code Style and Structure\n\n- Write concise, technical TypeScript code with accurate examples.\n- Use functional and declarative programming patterns; avoid classes.\n- Prefer iteration and modularization over code duplication.\n- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).\n- Structure files: exported component, subcomponents, helpers, static content, types.\n- Use console.log({ value }) instead of console.log(value)\n- Use onCallback instead of handleCallback\n- Use flex and gap instead of space-x-n and space-y-n\n- Use cn to compose class names\n- Just pass ref directly to the component because of react 19\n\n## Naming Conventions\n\n- Use lowercase with dashes for directories (e.g., components/auth-wizard).\n- Favor named exports for components.\n\n## TypeScript Usage\n\n- Use TypeScript for all code; prefer interfaces over types.\n- Avoid enums; use maps instead.\n- Use functional components with TypeScript interfaces.\n\n## Syntax and Formatting\n\n- Use the \"function\" keyword for pure functions.\n- Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.\n- Use declarative JSX.\n\n## UI and Styling\n\n- Use Shadcn UI, Base UI, Radix, and Tailwind for components and styling.\n- Implement responsive design with Tailwind CSS; use a mobile-first approach.\n\n## Performance Optimization\n\n- Minimize 'use client', 'useEffect', and 'setState'; favor React Server Components (RSC).\n- Wrap client components in Suspense with fallback.\n- Use dynamic loading for non-critical components.\n- Optimize images: use WebP format, include size data, implement lazy loading.\n\n## Key Conventions\n\n- Optimize Web Vitals (LCP, CLS, FID).\n- Limit 'use client':\n  - Favor server components and Next.js SSR.\n  - Use only for Web API access in small components.\n  - Avoid for data fetching or state management.\n- Follow Next.js docs for Data Fetching, Rendering, and Routing.\n\nMake sure not to start the dev server or run type of lint checking on agent mode.\n\n## React Patterns and Best Practices\n\n## Core Philosophy\n\n- **UIs are thin wrappers over data**: avoid using local state (like useState) unless absolutely necessary and it's independent of business logic\n- Even when local state seems needed, consider if you can flatten the UI state into a basic calculation\n- useState is only necessary if it's truly reactive and cannot be derived\n\n## State Management\n\n- **Choose state machines over multiple useStates**: multiple useState calls make code harder to reason about\n- Prefer a single state object with reducers for complex state logic\n- Co-locate related state rather than spreading it across multiple useState calls\n\n## Component Architecture\n\n- **Create new component abstractions when nesting conditional logic**\n- Move complex logic to new components rather than deeply nested conditionals\n- Use ternaries only for small, easily readable logic\n- Avoid top-level if/else statements in JSX; extract to components instead\n\n## Side Effects and Dependencies\n\n- **Avoid putting dependent logic in useEffects**: it causes misdirection about what the logic is doing\n- Choose to explicitly define logic rather than depend on implicit reactive behavior\n- When useEffect is necessary, be explicit about dependencies and cleanup\n- Prefer derived state and event handlers over effect-driven logic\n\n## Timing and Async Patterns\n\n- **setTimeouts are flaky and usually a hack**: always provide a comment explaining why setTimeout is needed\n- Consider alternatives like:\n  - Proper loading states\n  - Suspense boundaries\n  - Event-driven patterns\n  - State machines with delayed transitions\n  - requestAnimateFrame and queuMicrotask\n\n## Code Quality Impact\n\nThese patterns prevent subtle bugs that pile up into major issues. While code may \"work\" without following these guidelines, violations often lead to:\n\n- Hard-to-debug timing issues\n- Unexpected re-renders\n- State synchronization problems\n- Complex refactoring requirements\n\n## Examples\n\n### ❌ Avoid: Multiple useState\n\n```tsx\nconst [loading, setLoading] = useState(false);\nconst [error, setError] = useState(null);\nconst [data, setData] = useState(null);\n```\n\n### ✅ Prefer: State machine\n\n```tsx\nfunction useLazyRef<T>(fn: () => T) {\n  const ref = React.useRef<T | null>(null);\n\n  if (ref.current === null) {\n    ref.current = fn();\n  }\n\n  return ref as React.RefObject<T>;\n}\n\ninterface Store<T> {\n  subscribe: (callback: () => void) => () => void\n  getState: () => T\n  setState: <K extends keyof T>(key: K, value: T[K]) => void\n  notify: () => void\n}\n\nfunction createStore<T>(\n  listenersRef: React.RefObject<Set<() => void>>,\n  stateRef: React.RefObject<T>,\n  onValueChange?: Partial<{\n    [K in keyof T]: (value: T[K], store: Store<T>) => void\n  }>\n): Store<T> {\n  const store: Store<T> = {\n    subscribe: (cb) => {\n      listenersRef.current.add(cb);\n      return () => listenersRef.current.delete(cb);\n    },\n    getState: () => stateRef.current,\n    setState: (key, value) => {\n      if (Object.is(stateRef.current[key], value)) return;\n      stateRef.current[key] = value;\n      onValueChange?.[key]?.(value, store);\n      store.notify();\n    },\n    notify: () => {\n      for (const cb of listenersRef.current) {\n        cb();\n      }\n    },\n  };\n\n  return store;\n}\n\nfunction useStoreSelector<T, U>(\n  store: Store<T>,\n  selector: (state: T) => U\n): U {\n  return React.useSyncExternalStore(\n    store.subscribe,\n    () => selector(store.getState()),\n    () => selector(store.getState()),\n  );\n}\n```\n\n### ❌ Avoid: Complex conditionals in JSX\n\n```tsx\nreturn (\n  <div>\n    {user ? (\n      user.isAdmin ? (\n        <AdminPanel />\n      ) : user.isPremium ? (\n        <PremiumDashboard />\n      ) : (\n        <BasicDashboard />\n      )\n    ) : (\n      <LoginForm />\n    )}\n  </div>\n);\n```\n\n### ✅ Prefer: Component abstraction\n\n```tsx\nfunction UserDashboard({ user }) {\n  if (!user) return <LoginForm />;\n  if (user.isAdmin) return <AdminPanel />;\n  if (user.isPremium) return <PremiumDashboard />;\n  return <BasicDashboard />;\n}\n```\n\n### ❌ Avoid: Effect-driven logic\n\n```tsx\nuseEffect(() => {\n  if (user && user.preferences) {\n    setTheme(user.preferences.theme);\n  }\n}, [user]);\n```\n\n### ✅ Prefer: Derived values\n\n```tsx\nconst theme = user?.preferences?.theme ?? 'default';\n```\n\n## You Might Not Need an Effect\n\n> Reference: [You Might Not Need an Effect](https://react.dev/learn/you-might-not-need-an-effect)\n\nEffects are an escape hatch for synchronizing with **external systems** (non-React widgets, network, browser DOM). If there is no external system involved, you shouldn't need an Effect.\n\n### When to remove Effects\n\n- **Don't transform data for rendering in Effects**: calculate at the top level of your component; it re-runs automatically when props/state change\n- **Don't handle user events in Effects**: use the corresponding event handler where you know exactly what happened\n- **Don't update state based on props or state**: derive it during rendering instead of using Effect + setState (avoids extra render passes)\n- **Don't chain Effects** that each adjust state to trigger each other; calculate what you can during rendering and do the rest in event handlers\n- **Don't notify parent components about state changes via Effects**: call the parent's callback in the same event handler that updates state, so React batches both updates in one pass\n- **Don't pass data from child to parent via Effects**: lift the data fetching to the parent and pass it down as props\n\n### When Effects are appropriate\n\n- Synchronizing with external systems (jQuery widgets, browser APIs, network)\n- Analytics events that fire because the component was **displayed** (not because of a user action)\n- Data fetching (but always add cleanup to avoid race conditions, and prefer framework-level solutions)\n\n### Patterns to use instead of Effects\n\n| Instead of... | Do this |\n| --- | --- |\n| Effect + setState for derived values | `const fullName = firstName + ' ' + lastName;` |\n| Effect to cache expensive calculations | `const result = useMemo(() => expensiveFn(a, b), [a, b]);` |\n| Effect to reset state when a prop changes | Pass a `key` prop to force remounting |\n| Effect to adjust partial state on prop change | Store the selected **ID** instead of the selected **item**, and derive the item during render |\n| Effect to share logic between event handlers | Extract a plain function and call it from both handlers |\n| Effect to subscribe to an external store | Use `useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)` |\n\n### ❌ Avoid: Resetting state via Effect\n\n```tsx\nuseEffect(() => {\n  setComment('');\n}, [userId]);\n```\n\n### ✅ Prefer: Key-based reset\n\n```tsx\n<Profile userId={userId} key={userId} />\n```\n\n### ❌ Avoid: Storing derived state + syncing with Effect\n\n```tsx\nconst [visibleTodos, setVisibleTodos] = useState([]);\nuseEffect(() => {\n  setVisibleTodos(getFilteredTodos(todos, filter));\n}, [todos, filter]);\n```\n\n### ✅ Prefer: Calculate during rendering\n\n```tsx\nconst visibleTodos = getFilteredTodos(todos, filter);\n```\n\n### ❌ Avoid: Event-specific logic in an Effect\n\n```tsx\nuseEffect(() => {\n  if (product.isInCart) {\n    showNotification(`Added ${product.name} to the cart!`);\n  }\n}, [product]);\n```\n\n### ✅ Prefer: Logic in the event handler\n\n```tsx\nfunction onProductBuy() {\n  addToCart(product);\n  showNotification(`Added ${product.name} to the cart!`);\n}\n```\n\n### ❌ Avoid: Chained Effects\n\n```tsx\nuseEffect(() => { if (card?.gold) setGoldCardCount(c => c + 1); }, [card]);\nuseEffect(() => { if (goldCardCount > 3) { setRound(r => r + 1); setGoldCardCount(0); } }, [goldCardCount]);\nuseEffect(() => { if (round > 5) setIsGameOver(true); }, [round]);\n```\n\n### ✅ Prefer: Derive + compute in event handler\n\n```tsx\nconst isGameOver = round > 5;\n\nfunction onCardPlace(nextCard) {\n  setCard(nextCard);\n  if (nextCard.gold) {\n    if (goldCardCount < 3) setGoldCardCount(goldCardCount + 1);\n    else { setGoldCardCount(0); setRound(round + 1); }\n  }\n}\n```\n\n### Data fetching: always add cleanup\n\n```tsx\nuseEffect(() => {\n  let ignore = false;\n  fetchResults(query, page).then(json => {\n    if (!ignore) setResults(json);\n  });\n  return () => { ignore = true; };\n}, [query, page]);\n```\n\n## useMemo\n\n> Reference: [useMemo](https://react.dev/reference/react/useMemo)\n\n`useMemo` caches the **result** of a calculation between re-renders.\n\n### When to use useMemo\n\n- The calculation is **noticeably slow** (~1ms+ measured with `console.time`) and its dependencies rarely change\n- The result is passed as a prop to a `memo`-wrapped component (referential stability matters)\n- The value is used as a dependency of another Hook (useMemo, useCallback, useEffect)\n\n### When NOT to use useMemo\n\n- The calculation is cheap; just compute it inline\n- You're not passing the result to a memoized child or using it as a Hook dependency\n- A dependency changes on every render anyway (memoization is broken)\n\n### Prefer alternatives to useMemo\n\n1. **Accept JSX as children**: wrapper components that accept `children` let React skip re-rendering children when wrapper state updates\n2. **Keep state local**: don't lift transient state (forms, hover) higher than necessary\n3. **Keep rendering pure**: if re-rendering causes bugs, fix the bug instead of adding memoization\n4. **Remove unnecessary Effects** that update state, since chains of Effect-driven updates are the most common performance problem\n5. **Move objects/functions inside Effects** instead of memoizing them outside\n\n### ❌ Avoid: Effect + setState for derived computation\n\n```tsx\nconst [visibleTodos, setVisibleTodos] = useState([]);\nuseEffect(() => {\n  setVisibleTodos(getFilteredTodos(todos, filter));\n}, [todos, filter]);\n```\n\n### ✅ Prefer: Inline calculation (if cheap)\n\n```tsx\nconst visibleTodos = getFilteredTodos(todos, filter);\n```\n\n### ✅ Prefer: useMemo (if expensive)\n\n```tsx\nconst visibleTodos = useMemo(\n  () => getFilteredTodos(todos, filter),\n  [todos, filter]\n);\n```\n\n### ❌ Avoid: Object dependency that breaks memoization\n\n```tsx\nconst searchOptions = { matchMode: 'whole-word', text };\nconst visibleItems = useMemo(() => searchItems(allItems, searchOptions), [allItems, searchOptions]);\n```\n\n### ✅ Prefer: Move object inside useMemo\n\n```tsx\nconst visibleItems = useMemo(() => {\n  const searchOptions = { matchMode: 'whole-word', text };\n  return searchItems(allItems, searchOptions);\n}, [allItems, text]);\n```\n\n## useCallback\n\n> Reference: [useCallback](https://react.dev/reference/react/useCallback)\n\n`useCallback` caches the **function itself** between re-renders. It is equivalent to `useMemo(() => fn, deps)`.\n\n### When to use useCallback\n\n- Passing a function as a prop to a `memo`-wrapped component (so it can skip re-rendering)\n- The function is used as a dependency of another Hook (useEffect, useMemo, useCallback)\n- Writing a custom Hook that returns functions (always wrap returned functions in useCallback)\n\n### When NOT to use useCallback\n\n- The child component is not wrapped in `memo`; useCallback has no benefit\n- A dependency changes on every render anyway\n- The function is only used locally and not passed as a prop or Hook dependency\n\n### ❌ Avoid: useCallback without memo on the child\n\n```tsx\nfunction Parent() {\n  const onClick = useCallback(() => { /* ... */ }, []);\n  return <Child onClick={onClick} />; // Child is NOT memo-wrapped, useCallback is pointless\n}\n```\n\n### ✅ Prefer: useCallback paired with memo\n\n```tsx\nconst Child = memo(function Child({ onClick }) { /* ... */ });\n\nfunction Parent() {\n  const onClick = useCallback(() => { /* ... */ }, [dep]);\n  return <Child onClick={onClick} />;\n}\n```\n\n### ✅ Prefer: Move functions inside Effects instead of wrapping in useCallback\n\n```tsx\n// Instead of useCallback + function dependency in Effect:\nuseEffect(() => {\n  function createOptions() {\n    return { serverUrl: 'https://localhost:1234', roomId };\n  }\n  const connection = createConnection(createOptions());\n  connection.connect();\n  return () => connection.disconnect();\n}, [roomId]);\n```\n\n### Use updater functions to remove state dependencies\n\n```tsx\n// ❌ Depends on todos\nconst onTodoAdd = useCallback((text) => {\n  setTodos([...todos, { id: nextId++, text }]);\n}, [todos]);\n\n// ✅ No dependency on todos\nconst onTodoAdd = useCallback((text) => {\n  setTodos(todos => [...todos, { id: nextId++, text }]);\n}, []);\n```\n\n### Custom Hooks should wrap returned functions\n\n```tsx\nfunction useRouter() {\n  const { dispatch } = useContext(RouterStateContext);\n\n  const navigate = useCallback((url) => {\n    dispatch({ type: 'navigate', url });\n  }, [dispatch]);\n\n  return { navigate };\n}\n```\n</yakaai_skills>"}