react-hook

- Callbacks passed to hooks must be wrapped in useCallback

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "react-hook" with this command: npx skills add bumgeunsong/daily-writing-friends/bumgeunsong-daily-writing-friends-react-hook

React Hook Patterns

Overview

Core principles:

  • Callbacks passed to hooks must be wrapped in useCallback

  • One hook per file, organized by feature domain

  • Only abstract when logic is reused or complex

Custom Hook Rules

Rule Why

Must start with use

React's hook detection

One hook per file Maintainability

Never call conditionally Breaks hook order

Never return side effects Unpredictable behavior

Type inputs and outputs Clarity and safety

Test in isolation Reliability

On memoization: Only use useMemo /useCallback when logic is computationally heavy. Otherwise they degrade readability without meaningful benefit. Exception: callbacks passed TO hooks (see stability section below).

When to Use

  • Passing a callback to a custom hook

  • Fixing react-hooks/exhaustive-deps ESLint warnings

  • Debugging "why is this re-rendering every keystroke?"

  • Seeing errors like addRange(): The given range isn't in document

The Problem

Inline callback → Hook depends on it → Hook's output in useMemo → Cascade of re-renders

When you fix an ESLint exhaustive-deps warning by adding a dependency, check if that dependency is STABLE. If not, you've created a re-render loop.

Core Pattern

// ❌ BAD - inline function recreated every render const { handler } = useCustomHook({ onComplete: (result) => doSomething(result) });

// ✅ GOOD - stable reference const onComplete = useCallback((result) => doSomething(result), []); const { handler } = useCustomHook({ onComplete });

Quick Reference

Situation Action

Passing callback to hook Wrap in useCallback

ESLint says add dependency Check if dependency is stable first

Hook output changes every render Trace dependency chain backwards

Component re-renders on every keystroke Check for inline callbacks in hook calls

Red Flags - STOP and Check

If you're about to:

  • Pass an inline arrow function to a custom hook

  • Add a callback to useMemo /useCallback deps without checking stability

  • "Fix" exhaustive-deps by just adding the missing dep

STOP. Trace the dependency chain. Is everything stable?

Common Mistakes

Mistake Fix

"ESLint said add it, so I did" Check if the dep is stable BEFORE adding

"It's just a small callback" Size doesn't matter, stability does

"The hook should handle this" Caller is responsible for stable refs

Dependency Chain Debugging

When something re-renders unexpectedly:

  • Find the useMemo /useCallback that's recreating

  • Check each dependency - which one changed?

  • Trace that dependency back - why did IT change?

  • Keep tracing until you find the unstable root

  • Wrap the root in useCallback with stable deps

Real-World Impact

The bug: Quill editor threw addRange(): The given range isn't in document on every keystroke.

Root cause:

  • ESLint fix changed useMemo deps from [toast] to [imageHandler]

  • imageHandler depended on insertImage via useCallback

  • insertImage was inline (new function every render)

  • Chain: insertImage ↻ imageHandler ↻ modules ↻ ReactQuill re-init

Fix: Wrap insertImage in useCallback with [] deps.

Time saved by knowing pattern: 2+ hours of debugging → 5 minutes.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

firebase-functions

No summary provided by upstream source.

Repository SourceNeeds Review
General

pr-stacking

No summary provided by upstream source.

Repository SourceNeeds Review
General

api-layer

No summary provided by upstream source.

Repository SourceNeeds Review