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 就会非常有底气了。

相关推荐
东方小月7 小时前
从零开发一个 Coding Agent(四):使用状态机校验大模型事件流
前端·人工智能·后端
Csvn7 小时前
🧩 ESM vs CJS 混用的 7 个「天坑」——从 TypeScript 编译到 Node 与浏览器
前端
Csvn7 小时前
🎯 Web 性能 API 集合:Performance Observer 的 5 个冷门妙用
前端
Csvn8 小时前
深入 React 闭包陷阱:从根源上理解并根治 stale closure
前端
whyfail8 小时前
前端学 Spring Boot(8):接口为什么越用越慢?
前端·spring boot·后端
用户059540174468 小时前
LangChain 记忆测试踩坑实录:这两个坑让我排查了 4 小时
前端·css
程序员黑豆8 小时前
鸿蒙应用开发:@Monitor 装饰器使用教程
前端·harmonyos
SamChan909 小时前
在Web应用中集成PDF多语言翻译功能:PDFTranslator API实战指南
前端·python·ai·pdf·yapi·机器翻译
kyriewen9 小时前
AI Agent 9秒删光了生产数据库——我给自己的项目做了5个紧急检查
前端·ai编程·claude
IT_陈寒10 小时前
JavaScript的this又双叒叕让我怀疑人生了
前端·人工智能·后端