mcpField
R
react-hooks

react-hooks

github.com/claude-dev-suite开发4636 次安装3 天前更新
代码仓库

关于 react-hooks

面向 React 开发者的 Hooks 参考技能,涵盖内置 Hook、自定义 Hook 模式、规则与常见问题,帮助编写和排查组件逻辑。

主要功能

  1. 01内置 Hook 用途与时机参考
  2. 02自定义 Hook 常用模式
  3. 03Hooks 调用规则说明
  4. 04常见陷阱与问题排查

适用场景

  1. 01选择适合组件状态的 Hook
  2. 02实现数据获取或防抖逻辑
  3. 03排查依赖项与闭包问题

MCP 相关

文档建议通过 `mcp__documentation__fetch_docs` 获取 React Hooks 的详细资料。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill react-hooks

安装后在 Claude Code 中输入/react-hooks确认已加载。

附带文件quick-ref/hooks-cheatsheet.md

详细介绍

React Hooks

深入了解:使用 mcp__documentation__fetch_docs,指定技术:react,主题:hooks,获取有关所有 React Hooks 和自定义 Hook 模式的完整文档。

内置 Hooks 参考

状态 Hooks
Hook用途使用时机
useState组件本地状态简单的状态值
useReducer复杂的状态逻辑包含多个子值或复杂更新
// useState - simple state
const [count, setCount] = useState(0);
const [user, setUser] = useState<User | null>(null);

// useReducer - complex state
type Action = { type: 'increment' } | { type: 'decrement' } | { type: 'reset'; payload: number };

function reducer(state: number, action: Action): number {
  switch (action.type) {
    case 'increment': return state + 1;
    case 'decrement': return state - 1;
    case 'reset': return action.payload;
  }
}

const [count, dispatch] = useReducer(reducer, 0);
副作用 Hooks
Hook用途时机
useEffect副作用、订阅绘制后
useLayoutEffectDOM 测量绘制前
useInsertionEffect注入 CSS-in-JSDOM 变更前
// useEffect - most common
useEffect(() => {
  const subscription = api.subscribe(id);
  return () => subscription.unsubscribe(); // Cleanup
}, [id]); // Dependency array

// useLayoutEffect - measure DOM before paint
useLayoutEffect(() => {
  const { height } = ref.current.getBoundingClientRect();
  setHeight(height);
}, []);
Context Hook
const ThemeContext = createContext<Theme>('light');

function Component() {
  const theme = useContext(ThemeContext); // Reads nearest Provider value
  return <div className={theme}>...</div>;
}
Ref Hooks
// DOM reference
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
  inputRef.current?.focus();
}, []);

// Mutable value (no re-render on change)
const renderCount = useRef(0);
renderCount.current++; // Doesn't cause re-render

// useImperativeHandle - customize ref exposed to parent
useImperativeHandle(ref, () => ({
  focus: () => inputRef.current?.focus(),
  scrollIntoView: () => inputRef.current?.scrollIntoView(),
}), []);
性能 Hooks
// useMemo - cache expensive calculations
const sortedItems = useMemo(() => {
  return items.sort((a, b) => a.name.localeCompare(b.name));
}, [items]);

// useCallback - cache function references
const handleClick = useCallback((id: string) => {
  setSelected(id);
}, []); // Empty deps = stable reference

// useTransition - non-blocking state updates
const [isPending, startTransition] = useTransition();
startTransition(() => {
  setSearchResults(filterLargeList(query)); // Won't block UI
});

// useDeferredValue - defer updating expensive UI
const deferredQuery = useDeferredValue(query);
// UI shows stale value while new value computes
其他 Hooks
// useId - unique IDs for accessibility
const id = useId();
<label htmlFor={id}>Email</label>
<input id={id} type="email" />

// useSyncExternalStore - subscribe to external stores
const state = useSyncExternalStore(
  store.subscribe,
  store.getSnapshot,
  store.getServerSnapshot // Optional: for SSR
);

Hooks 规则

1. 只能在顶层调用
// BAD - conditional hook
if (condition) {
  const [value, setValue] = useState(0); // ERROR
}

// BAD - hook in loop
for (const item of items) {
  useEffect(() => {}, [item]); // ERROR
}

// GOOD - conditional logic inside hook
const [value, setValue] = useState(0);
useEffect(() => {
  if (condition) {
    // Do something
  }
}, [condition]);
2. 只能在 React 函数中调用
// GOOD - in component
function Component() {
  const [state, setState] = useState(0);
}

// GOOD - in custom hook
function useCustomHook() {
  const [state, setState] = useState(0);
  return state;
}

// BAD - regular function
function helper() {
  const [state, setState] = useState(0); // ERROR
}

自定义 Hooks 模式

基本模式
function useLocalStorage<T>(key: string, initialValue: T) {
  const [value, setValue] = useState<T>(() => {
    const stored = localStorage.getItem(key);
    return stored ? JSON.parse(stored) : initialValue;
  });

  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue] as const;
}

// Usage
const [theme, setTheme] = useLocalStorage('theme', 'dark');
带加载/错误状态的获取 Hook
interface UseFetchResult<T> {
  data: T | null;
  loading: boolean;
  error: Error | null;
  refetch: () => void;
}

function useFetch<T>(url: string): UseFetchResult<T> {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<Error | null>(null);

  const fetchData = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const response = await fetch(url);
      if (!response.ok) throw new Error(`HTTP ${response.status}`);
      setData(await response.json());
    } catch (e) {
      setError(e instanceof Error ? e : new Error(String(e)));
    } finally {
      setLoading(false);
    }
  }, [url]);

  useEffect(() => {
    fetchData();
  }, [fetchData]);

  return { data, loading, error, refetch: fetchData };
}
防抖 Hook
function useDebounce<T>(value: T, delay: number): T {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const timer = setTimeout(() => setDebouncedValue(value), delay);
    return () => clearTimeout(timer);
  }, [value, delay]);

  return debouncedValue;
}

// Usage
const [query, setQuery] = useState('');
const debouncedQuery = useDebounce(query, 300);

useEffect(() => {
  if (debouncedQuery) {
    searchAPI(debouncedQuery);
  }
}, [debouncedQuery]);
切换 Hook
function useToggle(initialValue = false) {
  const [value, setValue] = useState(initialValue);

  const toggle = useCallback(() => setValue(v => !v), []);
  const setTrue = useCallback(() => setValue(true), []);
  const setFalse = useCallback(() => setValue(false), []);

  return { value, toggle, setTrue, setFalse };
}

// Usage
const { value: isOpen, toggle, setFalse: close } = useToggle();
上一个值 Hook
function usePrevious<T>(value: T): T | undefined {
  const ref = useRef<T>();

  useEffect(() => {
    ref.current = value;
  }, [value]);

  return ref.current;
}

// Usage - detect changes
const prevCount = usePrevious(count);
useEffect(() => {
  if (prevCount !== undefined && prevCount !== count) {
    console.log(`Count changed from ${prevCount} to ${count}`);
  }
}, [count, prevCount]);
媒体查询 Hook
function useMediaQuery(query: string): boolean {
  const [matches, setMatches] = useState(() =>
    window.matchMedia(query).matches
  );

  useEffect(() => {
    const mediaQuery = window.matchMedia(query);
    const handler = (e: MediaQueryListEvent) => setMatches(e.matches);

    mediaQuery.addEventListener('change', handler);
    return () => mediaQuery.removeEventListener('change', handler);
  }, [query]);

  return matches;
}

// Usage
const isMobile = useMediaQuery('(max-width: 768px)');
const prefersDark = useMediaQuery('(prefers-color-scheme: dark)');

常见陷阱

1. 缺少依赖项
// BAD - missing userId dependency
useEffect(() => {
  fetchUser(userId);
}, []); // Lint error: userId missing

// GOOD
useEffect(() => {
  fetchUser(userId);
}, [userId]);
2. 对象/数组依赖项
// BAD - new object every render
useEffect(() => {
  doSomething(options);
}, [{ page: 1, limit: 10 }]); // Always triggers

// GOOD - use useMemo or primitive values
const options = useMemo(() => ({ page, limit }), [page, limit]);
useEffect(() => {
  doSomething(options);
}, [options]);
3. 过期闭包
// BAD - stale count value
useEffect(() => {
  const interval = setInterval(() => {
    setCount(count + 1); // Always uses initial count
  }, 1000);
  return () => clearInterval(interval);
}, []); // count not in deps but used

// GOOD - functional update
useEffect(() => {
  const interval = setInterval(() => {
    setCount(c => c + 1); // Uses current value
  }, 1000);
  return () => clearInterval(interval);
}, []);

不要使用此技能的情况

  • React 19 的 use() Hook——改用 react-19 技能
  • Context API 实现——如需完整的 Context 模式,请使用 react-context 技能
  • 表单状态管理——改用 react-forms 或 react-hook-form 技能
  • 性能优化——如需详细的优化策略,请使用 react-performance 技能

反模式

反模式问题解决方案
有条件地调用 Hooks破坏 Hook 顺序始终在组件顶层调用
缺少依赖项闭包过期将所有依赖项包含在数组中
状态存在时使用空依赖数组回调中的状态过期使用函数式更新或添加依赖项
将对象/数组用作依赖项每次都会触发使用 useMemo 或单独的基本类型值
用 useEffect 派生状态产生额外的渲染周期在渲染期间计算
不清理副作用内存泄漏返回清理函数
自定义 Hook 未以 'use' 开头Linter 不会检查将所有 Hooks 命名为 use*

快速故障排除

问题可能原因修复方法
Hook 顺序错误有条件地调用 Hook将条件移入 Hook 内部
无限循环依赖项缺失或错误检查依赖项数组
闭包过期缺少依赖项添加到依赖项数组,或使用函数式更新
每次渲染都会运行副作用缺少依赖项数组添加 [] 或正确的依赖项
未运行清理未返回函数从 useEffect 返回清理函数
useCallback 不起作用创建了新的内联函数检查依赖项数组
useMemo 未进行记忆化依赖项发生变化检查依赖项是否稳定

参考

评论

支持 Markdown