跳转到主要内容

编写自己的 Hooks

自定义 Hook 的本质不是“复用 UI”,而是复用状态逻辑:订阅、缓存、派生、节流/防抖、同步外部系统…… 当你发现多个组件里出现了相同的 Hook 组合与 Effect 逻辑,就该考虑抽出去。

例子:抽取“在线状态”逻辑

这个逻辑包含 State + Effect + 清理,非常适合封装成 Hook,然后在多个组件里复用。

TypeScript
import { useEffect, useState } from 'react';

function useOnlineStatus() {
  const [isOnline, setIsOnline] = useState(true);

  useEffect(() => {
    function onOnline() {
      setIsOnline(true);
    }
    function onOffline() {
      setIsOnline(false);
    }

    window.addEventListener('online', onOnline);
    window.addEventListener('offline', onOffline);
    return () => {
      window.removeEventListener('online', onOnline);
      window.removeEventListener('offline', onOffline);
    };
  }, []);

  return isOnline;
}

export default function StatusBar() {
  const isOnline = useOnlineStatus();
  return <p>{isOnline ? '在线' : '离线'}</p>;
}

常见模式:useDebouncedValue

防抖在搜索输入、自动保存、筛选列表里很常见。

TypeScript
import { useEffect, useState } from 'react';

export function useDebouncedValue<T>(value: T, delayMs: number) {
  const [debounced, setDebounced] = useState(value);

  useEffect(() => {
    const id = window.setTimeout(() => setDebounced(value), delayMs);
    return () => window.clearTimeout(id);
  }, [value, delayMs]);

  return debounced;
}
常见误区
  • 把组件渲染/样式也塞进 Hook:Hook 应该负责逻辑,UI 交给组件。
  • 在 Hook 里根据条件调用 Hook:违反 Hooks 规则,会导致状态错位。
  • Hook 返回值不稳定导致子组件频繁渲染:必要时用 useMemo/useCallback

下一步

动手练习

运行并修改下面的组件,熟悉交互式示例的编辑与预览。

🌐浏览器运行
编写自己的 Hooks - React 文档 - React 文档