react的useEffect的依赖问题?

import React, {useEffect, useState} from 'react';
import Editor from 'ewt-question-tinyeditor';

export default () => {
  const [data, setData] = useState({name: 1});
  const [list, setList] = useState([]);



  useEffect(() => {
    console.log(data, 'data--------');
    console.log(list,'---list');
  }, [data]);

  return (
    <div>
      <div onClick={() => {
        setData({name: new Date()});
        setList([{age: new Date()}]);
      }}>
        点击修改data数据
      </div>
      <div onClick={() => {
        setList([{age: new Date()}]);
      }}>
        点击修改list数据
      </div>
    </div>
  );
};
  1. 我先点击一次修改list数据,更新list数据
  2. 点击一次修改data数据,更新list和data数据
  3. 有个疑问 :
    然后useEffect中因为依赖的数据data修改了,
    打印的data是最新的数据,
    为什么打印出来的list数据也是最新的
    不是useEffect的第二个参数中的依赖没有list,luseEffect函数中的list不是应该是旧的吗?
阅读 3.2k
5 个回答
  1. useEffect 在组件渲染完成之后调用,一般处理组件副作用(如:订阅/取消订阅一些东西)。
  2. React 18 对批量更新做了优化,可以在任何位置自动批量更新(batched updates)。
  3. useState 在同一个 React 组件中,同一位置批量调用时,为了性能(避免 rerender),合并 setState 操作。

这里的两个 useState 在一起调用更新,避免过多的组件重复渲染, React 内部将其合并批量更新数据。所以当 data 更新的同时 list 也一起更新了。

因为依赖变化只是告诉useEffect:你依赖的东西有变化,你应该重新执行回调函数
不是告诉useEffect:你依赖的某某项发生了变化,你应该更新该依赖项

当然这种现象不能当功能使用,因为useEffect与渲染并不同步,类似的现象不一定能稳定复现,推荐的做法是把useEffect中引用的所有state都写进依赖项。

你觉得 useEffect 的依赖里只写了 data,所以 list 应该是上一次的数据。但其实不是,react 每次运行都像一个快照一样,它会拿这一次函数执行时候对应的值来渲染,依赖项仅仅是用于告诉 react 要不要执行 useEffect 钩子里的函数,并不影响你大的函数的重新渲染和读值,这次读值里的 list 和 data 就应该是最新的。

像你的例子里,只要你点击改变了 list 或者 data 的值,react 都会重新渲染,这个部分和你的 useEffect 没关系。你比如你的 onClick 事件只修改 list ,那你的 useEffect 除了第一次渲染打印,后面都不打印的。

useEffect 第一个参数是回调函数,第二个参数是依赖参数。他会监听第二个参数的值的变化来触发回调。
你的例子中,回调函数监听data的变化,在数据更新时触发回调。而回调函数所取的变量跟data没关系,你打印的是外部定义的data和list.

给你捋捋流程

1.先点击一次修改list数据,更新list数据:

触发onclick => list 数据更新 => 此时,data 是{name: 1}, list 是 [{age: new Date()}] => 不触发useEffect,因为依赖没有list,不对list 做监听,页面重渲染

2.点击一次修改data数据,更新list和data数据:

触发onclick => list、data 数据更新 => 此时,data 是{name: new Date()}, list 是 [{age: new Date()}] => 因为依赖有data,监听到data改变,触发useEffect,页面重渲染

useEffect 的依赖项只是告诉它什么时候执行里面的函数,如你写的,当 data 改变时执行useEffect 里面的函数,触发打印,但无论useEffect 有没有触发,只要setState了,页面总会重渲染,state 总会改变,和useEffect 无关。

闲来无事随便回答的,措辞上大概是不严谨的,大致是这个道理。

推荐问题
宣传栏