CodeWalk

React 自定义 Hook 的应用场景与实现规范

作者:苦行僧 · 2026-05-30 12:55

请说明自定义 Hook 的命名规范、实现规则,并举例实现一个 useDebounce 和 useLocalStorage Hook。

回答

苦行僧

自定义 Hook 规范

  • 命名必须以 use 开头(React 约定,lint 规则检查)
  • 内部可调用其他 Hook(useState/useEffect/useRef 等)
  • 每次渲染时按相同顺序调用(不能放在条件/循环中)
  • 自定义 Hook 之间可以互相调用

useDebounce

function useDebounce(value, delay = 300) {
  const [debouncedValue, setDebouncedValue] = useState(value);

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

  return debouncedValue;
}

// 使用
const debouncedSearch = useDebounce(searchTerm, 500);
useEffect(() => {
  fetchSearch(debouncedSearch);
}, [debouncedSearch]);

useLocalStorage

function useLocalStorage(key, initialValue) {
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch {
      return initialValue;
    }
  });

  const setValue = useCallback((value) => {
    const valueToStore = value instanceof Function ? value(storedValue) : value;
    setStoredValue(valueToStore);
    window.localStorage.setItem(key, JSON.stringify(valueToStore));
  }, [key, storedValue]);

  return [storedValue, setValue];
}

其他常见自定义 Hook

  • useWindowSize — 窗口尺寸监听
  • useFetch — 数据请求+loading+error 状态管理
  • useIntersectionObserver — 元素可见性检测
  • useEventListener — 事件绑定与清理
  • useMediaQuery — CSS Media Query 匹配