【问题标题】:Reused React element prevents component updates重用 React 元素可防止组件更新
【发布时间】:2019-05-07 10:21:15
【问题描述】:

Foo 是一个应该只渲染一次的组件。这可以用于性能优化,尽管这只是纯粹的理论问题,没有解决任何特定的编码问题。

这可以通过使用shouldComponentUpdate或纯组件来实现,这是一个推荐的方法:

const Foo = () => <p>{Math.random()}</p>;
const FooOnce = React.memo(Foo);
const Bar = () => {
  const [, update] = useState();

  useEffect(() => {
    setTimeout(() => {
      update({});
    }, 500);
  }, []);

  return <>
    <FooOnce/>
  </>;
};

或者通过保留对 React 元素对象的引用并重用它:

const fooOnce = <Foo/>;
const Bar = () => {
  const [, update] = useState();

  useEffect(() => {
    setTimeout(() => {
      update({});
    }, 500);
  }, []);

  return <>
    {fooOnce}
  </>;
};

重用元素对象时不会重新渲染组件是直观的,但我从自己的经验中知道这一点,而不是从官方来源。这可能会导致createElement 调用少于纯组件,因此这可能被认为是一个好处。

所有 React 版本中都记录和预期这种行为吗?

是否有理由不以这种方式重用元素来防止组件更新?

【问题讨论】:

  • 为什么要确保组件不会被重新渲染?这通常意味着您正在尝试强制执行某些操作,并且通常在 React 中有更好的方法来实现这一点
  • @Aron 这个问题没有针对具体案例。我想这可以用作优化技术。

标签: reactjs


【解决方案1】:

所有 React 版本中都记录和预期这种行为吗?

不,我没有找到说明此行为的文档。

通过深入研究 React 源代码并设置一些断点,我发现通过保存和重用 createElement 结果 (const fooOnce = &lt;Foo/&gt;;),您每次都会有效地使用完全相同的 props 对象,而在每次渲染中调用 createElement 会创建一个新的道具对象每次。

目前,这确实有所不同,因为来自 Fiber 引擎的 function beginWork 中存在以下条件:if (oldProps !== newProps || hasLegacyContextChanged())

当 props 对象具有相同的标识时,react 立即认为该元素没有任何工作要做(甚至不调用render)。

这对我来说似乎很有可能继续工作,但当然不能保证这种优化将始终与这种确切的行为一致。

我指的是这里的代码: https://github.com/facebook/react/blob/c7398f33966c4fedcba2c48e915b379e8f334607/packages/react-reconciler/src/ReactFiberBeginWork.js#L2119

当你只使用普通函数时,你最终会调用渲染,并且由于输出不同,它会更新 DOM。

当你使用 React.memo 时,props 将具有相同的标识,但随后 react 会进入 memo 组件案例 (https://github.com/facebook/react/blob/c7398f33966c4fedcba2c48e915b379e8f334607/packages/react-reconciler/src/ReactFiberBeginWork.js#L2377) 并做一个 shallowEquals 比较 (https://github.com/facebook/react/blob/c7398f33966c4fedcba2c48e915b379e8f334607/packages/react-reconciler/src/ReactFiberBeginWork.js#L487)

是否有理由不以这种方式重用元素来防止组件更新?

这可以改变,所以我不会在生产代码中使用它。

除此之外,我会避免这种情况,因为组件是否更新的决定来自组件本身,因为现在要使用它,您需要更改使用者代码,而不仅仅是更改组件上的代码或添加包装器给它。

【讨论】:

    【解决方案2】:

    我的意思是,这是渲染组件 only once 与渲染 only ifonly if 是包含 only once condition 的超集。

    当然,渲染only once 可以通过两者来完成。但作为一个图书馆,他们只会记录适用于所有情况的内容。使用后一种变量使用方法只是决定我们如何看待事物。

    你在这里提出的观点很好。

    【讨论】:

      猜你喜欢
      • 2014-08-04
      • 2021-08-13
      • 2023-02-26
      • 1970-01-01
      • 1970-01-01
      • 2019-10-29
      • 2019-01-15
      • 2021-02-14
      • 1970-01-01
      相关资源
      最近更新 更多