标准答案

  1. React 通过 Hooks 的调用顺序来记录 useState、useEffect、useRef 等 Hook 对应的内部状态。
  2. 条件语句、循环、嵌套函数和提前 return 可能让某次渲染少调用或多调用 Hook,破坏顺序。
  3. Hook 应写在组件函数或自定义 Hook 的顶层,不要写在 if、for、回调函数或普通工具函数里。
  4. 条件逻辑应该放到 Hook 内部,例如 useEffect 里判断条件,而不是条件性调用 useEffect。
  5. 自定义 Hook 也必须遵守同样规则,并且命名通常以 use 开头,方便 lint 规则识别。

题目解析

这道题的核心是调用顺序,而不是语法偏好。Hook 本质上需要在多次 render 之间找到同一份状态槽位。

eslint-plugin-react-hooks 能提前发现大多数违反规则的写法,团队项目应开启。

如果确实要按条件执行副作用,可以始终调用 Hook,在 Hook 的回调内部判断是否执行。

代码示例

下面展示错误写法和正确写法的区别。

TSX
function UserPanel({ enabled }: { enabled: boolean }) {
  useEffect(() => {
    if (!enabled) {
      return
    }

    subscribeUser()
    return unsubscribeUser
  }, [enabled])

  return <div>用户面板</div>
}

常见误区

  • 在 if 条件里调用 useEffect 或 useState。
  • 在事件处理函数、普通工具函数里调用 Hook。
  • 自定义 Hook 内部按条件提前 return,导致后续 Hook 有时不执行。

作者信息