--- description: Custom hook patterns and best practices globs: ["apps/sim/**/use-*.ts", "apps/sim/**/hooks/**/*.ts"] --- # Hook Patterns ## Structure For server data, use a React Query hook from `hooks/queries/` — do NOT `useState` + `fetch` here (see `.claude/rules/sim-queries.md`). This pattern is for UI/orchestration hooks that hold UI-only state and wrap callbacks. ```typescript interface UseFeatureProps { id: string onSelect?: (item: Item) => void } export function useFeature({ id, onSelect }: UseFeatureProps) { // 1. Refs for stable dependencies const idRef = useRef(id) const onSelectRef = useRef(onSelect) // 2. UI-only state (never server data) const [isOpen, setIsOpen] = useState(false) // 3. Sync refs useEffect(() => { idRef.current = id onSelectRef.current = onSelect }, [id, onSelect]) // 4. Operations (useCallback with empty deps when using refs) const select = useCallback((item: Item) => { onSelectRef.current?.(item) setIsOpen(false) }, []) return { isOpen, setIsOpen, select } } ``` ## Rules 1. Single responsibility per hook 2. Props interface required 3. Refs for stable callback dependencies 4. Wrap returned functions in useCallback 5. Server data goes through React Query (`hooks/queries/`), never `useState` + `fetch` 6. Keep only UI/orchestration state in these hooks