重复使用的React元素会阻止组件更新

时间:2019-05-07 10:21:15

标签: reactjs

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版本中得到记录和预期?

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

2 个答案:

答案 0 :(得分:3)

  

此行为是否已在所有React版本中得到记录和预期?

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

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

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

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

对于我来说,这似乎很可能继续工作,但是当然不能保证这种优化将始终按照这种精确的行为进行。

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

仅使用普通模式时,您最终将调用render,并且由于输出不同,它将更新DOM。

当您使用React.memo时,道具将具有相同的身份,但是react将进入备注组件的大小写(https://github.com/facebook/react/blob/c7398f33966c4fedcba2c48e915b379e8f334607/packages/react-reconciler/src/ReactFiberBeginWork.js#L2377) 并进行“浅相等”比较(https://github.com/facebook/react/blob/c7398f33966c4fedcba2c48e915b379e8f334607/packages/react-reconciler/src/ReactFiberBeginWork.js#L487

  

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

这可以更改,因此我不会在生产代码中使用它。

除此之外,我将避免这种情况,因为有关组件更新的决定脱离了组件本身,因为现在要使用它,您需要更改使用者代码,而不仅仅是更改组件上的代码或添加包装器

答案 1 :(得分:0)

我的意思是,这是渲染组件only once与渲染only if的对比。 将only if作为包含only once condition的超集。

当然可以同时渲染only once。但是作为一个图书馆,他们只会记录在所有情况下都有效的内容。使用后一种变量使用方法只是在决定我们如何看待事物。

您在这里提出的要点。