react hook注意事项

写代码出错了,很少深入了解 hook。让ai给总结了一下。

这确实是 React 中非常核心且容易被忽视的"铁律"。React 的很多设计理念与传统的命令式编程(如 jQuery)或基于类的编程(Vue Options API)不太一样,因此有很多类似的"潜规则"和陷阱。

以下为您整理了 React 开发中必须知道的 6 个核心注意事项,掌握这些可以帮您避开 90% 的 Bug:

1. useEffect 依赖数组不能"撒谎" (Stale Closure / 闭包陷阱)

这是 Hook 最容易出 Bug 的地方。如果你在 useEffectuseCallback 内部使用了某个变量,但没有把它加到依赖数组 [] 中,Hook 内部就会一直引用旧的变量值

  • ❌ 错误写法:

    JavaScript 复制代码
    const [count, setCount] = useState(0);
    
    useEffect(() => {
      const timer = setInterval(() => {
        console.log(count); // 永远打印 0!因为这里的 count 是闭包捕获的初始值
      }, 1000);
      return () => clearInterval(timer);
    }, []); // 依赖数组是空的,导致 effect 只运行一次,内部永远拿着旧的 count
  • ✅ 正确写法:

    JavaScript 复制代码
    useEffect(() => {
      const timer = setInterval(() => {
        console.log(count);
      }, 1000);
      return () => clearInterval(timer);
    }, [count]); // 依赖 count,每次 count 变化,effect 会销毁旧的并重新运行

    或者使用函数式更新(如果不依赖外部变量触发 Effect):

    JavaScript 复制代码
    setCount(prevCount => prevCount + 1); // 这种写法不需要依赖 count

2. State 更新是"异步"的(快照特性)

调用 setState 后,状态不会立即改变。React 会把更新放入队列,等到下一次渲染时才会生效。

  • ❌ 常见误区:

    JavaScript 复制代码
    const handleClick = () => {
      setCount(count + 1);
      console.log(count); // 打印的仍然是旧值!不是 +1 后的值
    
      // 如果此时发请求,发出去的也是旧值
      fetchData(count); 
    };
  • ✅ 正确理解:

    如果你需要使用更新后的值,应该使用 useEffect 监听该值的变化,或者在 setState 中使用回调函数(仅用于计算新值)。

    JavaScript 复制代码
    useEffect(() => {
      console.log(count); // 这里才能拿到更新后的值
      fetchData(count);
    }, [count]);

3. 永远不要直接修改 State (Immutability / 不可变性)

React 比较状态是否变化是基于引用比较(Shallow Compare)。如果你直接修改对象属性,引用地址没变,React 就不知道数据变了,页面就不会刷新。

  • ❌ 错误写法:

    JavaScript 复制代码
    const [user, setUser] = useState({ name: 'Alice', age: 18 });
    
    const updateName = () => {
      user.name = 'Bob'; // 修改了内容,但对象引用没变
      setUser(user);     // React 认为前后是同一个对象,不触发重新渲染
    };
  • ✅ 正确写法:

    JavaScript 复制代码
    const updateName = () => {
      // 创建一个新对象(复制旧属性 + 覆盖新属性)
      setUser({ ...user, name: 'Bob' }); 
    };

4. 列表渲染必须有唯一的 key(且尽量不要用 index)

key 是 React 识别 DOM 节点的身份证。如果使用数组索引(index)作为 key,当列表顺序发生变化(插入、删除、排序)时,React 会复用错误的 DOM 节点,导致状态错乱。

  • ❌ 风险写法:

    JavaScript 复制代码
    // 如果列表顺序会变,千万别用 index
    {items.map((item, index) => <li key={index}>{item.name}</li>)}
  • ✅ 正确写法:

    JavaScript 复制代码
    // 使用数据中的唯一 ID
    {items.map((item) => <li key={item.id}>{item.name}</li>)}

5. useEffect 的清理函数 (Cleanup Function)

如果在 useEffect 中订阅了事件、设置了定时器或发起了请求,必须返回一个清理函数,否则会导致内存泄漏或逻辑错误(比如组件卸载了但定时器还在跑)。

  • ✅ 标准模板:

    JavaScript 复制代码
    useEffect(() => {
      // 1. 设置副作用
      const handleResize = () => console.log(window.innerWidth);
      window.addEventListener('resize', handleResize);
    
      // 2. 返回清理函数
      return () => {
        window.removeEventListener('resize', handleResize);
      };
    }, []);

6. React Strict Mode 下的"重复执行"

在开发环境(Development)中,为了帮你检查不纯的副作用,React 的 <StrictMode> 会故意将你的组件渲染两次useEffect 也会执行两次。

  • 现象 :你看控制台日志,发现 API 请求发了两次,或者 console.log 打印了两次。
  • 注意 :这不是 Bug,生产环境(Production)不会发生。不要为了解决这个问题去写奇怪的代码,而应该确保你的 Effect 是可以重复执行且无害的(做好清理工作)。

总结建议

您刚遇到的 "Hook 顺序与数量必须一致" 是 React 运行机制的物理限制(React 内部是靠数组索引来记录每个 Hook 的状态的,如果顺序乱了,状态就张冠李戴了)。

而上面提到的这 6 点,更多是逻辑和模式上的注意事项。掌握了这些,您写 React 就会非常有底气了。

相关推荐
赖龙4 小时前
pnpm vs npm
前端·npm·node.js
学如逆水,不进则退5 小时前
在线免费音频剪辑:NBTools 可视化波形裁剪 MP3/WAV,本地处理免上传
前端·音视频
Mh5 小时前
虚拟滚动真的比普通滚动性能更好吗?
前端·javascript·性能优化
pe7er5 小时前
React + Ant Design 中的 IME (输入法合成)安全输入组件
前端
Super 含6 小时前
Android 启动优化(二):TTID、TTFD 与 Macrobenchmark 启动性能测量
前端
Python私教6 小时前
别急着加 llms.txt:企业官网面向 AI 搜索的工程清单
前端·人工智能·seo
东方小月6 小时前
从零开发一个 Coding Agent(十三):实现安全的 read 文件读取工具
前端·人工智能·全栈
东方小月6 小时前
从零开发一个 Coding Agent(十二):实现版本化 JSONL 与真实 CLI 入口
前端·设计模式·前端框架
FL16238631298 小时前
室内易燃物识别易燃评估室内易燃程度识别分割数据集labelme格式1015张85类别
java·服务器·前端
用户059540174468 小时前
把 AI 长期记忆去重测试从 20 分钟压到 40 秒,重复率从 18% 干到 1.5%
前端·css