hooks useEffect 多个deps改变触发了多次 怎么解决呢?

a,b,c 同时改变,这个副作用被触发了3次,怎么让它只触发1次呢?
除了防抖还有什么办法吗

useEffect(() => {
    console.log(666)
}, [a, b, c])
阅读 10.2k
6 个回答

既然同时触发,只监听 a 不可以吗?

useEffect(() => {
    console.log(666)
}, [a])

react 更新机制是:收集要更新的属性,然后一次性更新,所以这个场景只会触发一次。

楼主是在什么样的场景下,同时改变被触发3次的。

怎么得出来的结论。。。。看看它触发了几次

function Foo() {
  const [a, setA] = useState(0);
  const [b, setB] = useState(0);
  useEffect(() => {
    console.log(+new Date(), a, b);
  }, [a, b]);
  return (
    <>
      a:{a}, b:{b}
      <button
        onClick={() => {
          setA(a + 1);
          setB(b + 1);
        }}
      >
        click me
      </button>
    </>
  );
}

你得考虑你这个副作用函数是在什么情况下需要执行, 里面是不是还需要增加条件判断去保证只执行一次.

光是依靠deps, 很多时候你没法去完全避免的, 那后面要是增加依赖怎么办呢? 首先得从你这个方法本身的逻辑入手才对.

举个例子

useEffect(() => {
    if (!a || !b || !c) return;
    console.log(123);
}, [a, b, c])

emmm 分页器相关参数会用一个对象去包裹。如果单独变化A 就变化对象中的A 并更新这个对象。 如果批量更新 就批量更新对象中的属性。然后再更新这个对象。

const [pagination,setPagination] = useState({size:10,page:0})
    // 单独更新
    setPagination({...pagination,size:20})
    // 批量更新
    setPagination({...pagination,size:20,page:0})
    // 依赖
    useEffect(() => {
    }, [pagination])

至于使用防抖为什么setState会有问题,set完视图不更新,还是上次的数据。一个可能的原因是因为防抖采用的是延迟开始前调用的策略。
setSize 完成后 就发请求去了。setpage应该发起的请求忽略了。可以参考lodash debounce的实现。采用延迟结束后调用。这样能保证最后一次更新的数据一定会发起一次effect。 但是不太推荐这样的做法。建议好好梳理依赖项。

react 更新机制是:收集要更新的属性,然后一次性更新,所以这个场景只会触发一次。

楼上有人说到这个,这个是不准确的。只有在原生事件的回调函数中才会这么处理,其他如setTimeout/Promise等情形的回调中是不会批量处理的。

React 18 改变了这个默认行为,使其在所有场景都批量更新(Batch Update)。

React 18 以下版本有个非公开 API unstable_batchedUpdates 可以强制手动批量更新。(不推荐使用,建议修改代码组织方式)

参见:https://github.com/reactwg/re...

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题