React

React Hooks 深度解析:超越 useState 与 useEffect

React Hooks 自 2019 年发布以来,彻底改变了 React 组件的编写方式。除了最常用的 useState 和 useEffect,还有一系列 Hook 能帮你写出更优雅、高性能的代码。

useRef:持久化可变值

useRef 返回一个可变的 ref 对象,其 .current 属性在组件的整个生命周期内保持不变。常见用途:

  • 访问 DOM 元素
  • 存储不需要触发重渲染的可变值(如上一次的 props)
  • 保存定时器 ID
function TextInput() {
  const inputRef = useRef(null);

  useEffect(() => {
    inputRef.current.focus();
  }, []);

  return <input ref={inputRef} />;
}

useCallback 与 useMemo:性能优化

这两个 Hook 用于缓存值和函数,避免不必要的重渲染:

const memoizedCallback = useCallback(
  (id) => fetchUser(id),
  [dependency]
);

const expensiveValue = useMemo(
  () => computeExpensiveValue(a, b),
  [a, b]
);

但要注意:不要过早优化。只在确实存在性能问题时才使用它们,否则反而增加代码复杂度。

useReducer:复杂状态管理

当状态逻辑复杂、涉及多个子值时,useReducer 是比 useState 更好的选择:

function reducer(state, action) {
  switch (action.type) {
    case 'increment': return { count: state.count + 1 };
    case 'decrement': return { count: state.count - 1 };
    default: return state;
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });
  return (
    <button onClick={() => dispatch({ type: 'increment' })}>
      Count: {state.count}
    </button>
  );
}

自定义 Hook:逻辑复用的最佳方式

自定义 Hook 让你将组件逻辑提取为可复用的函数。命名必须以 "use" 开头:

function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    const stored = localStorage.getItem(key);
    return stored ? JSON.parse(stored) : initialValue;
  });

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

  return [value, setValue];
}

Hook 使用规则

  1. 只在 React 函数组件或自定义 Hook 中调用 Hook
  2. 只在函数最顶层调用 Hook,不要在循环、条件或嵌套函数中调用
  3. ESLint 插件 eslint-plugin-react-hooks 可以自动检查这些规则