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版本中得到记录和预期?
有没有理由不以这种方式重用元素以防止组件更新?
答案 0 :(得分:3)
此行为是否已在所有React版本中得到记录和预期?
不,我没有找到说明此行为的文档。
通过深入研究React源代码并设置一些断点,我发现,通过保存和重用createElement结果(const fooOnce = <Foo/>;
),您每次都会有效地使用完全相同的props对象,同时在每个渲染创建中调用createElement每次都有一个新的道具对象。
当前,这确实有所不同,因为来自纤维引擎的function beginWork
中的以下条件:if (oldProps !== newProps || hasLegacyContextChanged())
当props对象具有相同的标识时,react立即认为该元素没有工作要做(甚至不调用render)。
对于我来说,这似乎很可能继续工作,但是当然不能保证这种优化将始终按照这种精确的行为进行。
仅使用普通模式时,您最终将调用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
。但是作为一个图书馆,他们只会记录在所有情况下都有效的内容。使用后一种变量使用方法只是在决定我们如何看待事物。
您在这里提出的要点。