【问题标题】:useEffect multiple dependencies - what is causing multiple renders?useEffect 多个依赖项 - 是什么导致了多次渲染?
【发布时间】:2022-09-23 19:03:32
【问题描述】:

因此,在下面的代码中,我想了解是什么导致组件多次重新渲染。尽管大部分时间这段代码运行没有任何问题,但有时它会导致浏览器变得无响应。

我无法确定导致该问题的原因,并相信重新审视 useEffect 可能是解决它的关键。

因为dispatch, props & addToast依赖于成功,我应该从依赖数组中删除它们并保持成功和错误吗?

有没有办法确定要保留哪些依赖项以及删除哪些依赖项?

useEffect(() => {
    if (success) {
      dispatch({ type: PRODUCT_RESET });
      dispatch(listProducts());
      props.onHide();
      addToast(\"Product has been added!\", {
        appearance: \"success\",
        autoDismiss: false,
      });
    } else if (error) {
      addToast(error, { appearance: \"error\", autoDismiss: false });
    }
  }, [dispatch, success, error, addToast, props]);
  • 去掉props,直接传递onHideprops 是每次渲染的新对象。
  • @OriDrori 正在使用 props.onHide() 因为 useEffect 正在模态组件中使用。在组件中解构它之前,我不能删除它,对吗?
  • 逐一删除依赖项并知道是哪一个导致了问题,似乎是道具导致了它。
  • @RitikBanger 浏览器在随机时间变得无响应,因此很难一一重现错误。

标签: reactjs react-hooks


【解决方案1】:

comment from @Ori Drori 移动到答案中。


[...] 如果父级重新渲染,子级将始终在一个新对象中收到它的props,即使其中没​​有任何变化。 [...]

来源:"Does React make any guarantees that the props object reference stays stable?"

您观察到的问题可能是dispatch 触发父组件重新渲染的原因,然后创建一个新的props 对象并因此重新渲染您的组件。这是一个无限的反馈循环。

您可以通过从依赖项列表中删除 props 并添加 props.onHide 来避免此问题。仅此一项可能还不够,因为如果props.onHide 的身份在父组件中定义为普通函数,则它的身份可能会发生变化。

您可能必须在父组件中使用useCallback 以确保函数的身份是稳定的,否则您可能会遇到同样的问题。


您还可以从依赖项列表中删除 dispatch,因为 react 保证它不会在渲染之间发生变化:

React 保证 dispatch 函数标识是稳定的,并且在重新渲染时不会改变。这就是为什么从 useEffectuseCallback 依赖列表中省略是安全的。

来源:"Hooks API Reference"


总而言之,您的依赖项列表如下所示:

useEffect(() => {
    // ...
}, [success, error, addToast, props.onHide]);

(如果在组件中定义了这个神秘的 listProducts 函数,您可能还必须将其添加为依赖项。)

在父组件中,您可能必须在定义 onHide 函数时使用 useCallback

// The child component could cause this component to re-render creating a 
// feedback loop.  The 'useCallback' prevents the identity of 'onHide' from 
// changing thus breaking the loop.
let onHide = useCallback(() => {
    // ...
}, [/* ... */]);

// ...

<Foo onHide={onHide} />

由于这显然有帮助,我将其从 a comment 移至答案:

This article briefly touches the whole useCallback thing, that helped me understand it.

【讨论】:

  • &lt;UserModal show={userModalShow} onHide={() =&gt; setUserModalShow(false)} /&gt; 这就是 onHide 道具在父组件中的使用方式。我应该如何将它与 useCallback 一起使用?
  • let onHide = useCallback(() =&gt; setUserModalShow(false), []);,然后是 &lt;UserModal onHide={onHide} /&gt;
  • 谢谢!那篇文章真的很有帮助! listProducts 函数实际上是一个 redux 导入,因此它没有在组件中定义,我不认为它需要作为依赖项添加。
猜你喜欢
  • 2020-11-27
  • 1970-01-01
  • 2022-11-25
  • 1970-01-01
  • 2020-12-23
  • 2021-07-23
  • 2020-04-23
  • 2020-01-06
  • 1970-01-01
相关资源
最近更新 更多