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 版本中是否都有记录并预期此行为?
不,我没有找到说明此行为的文档。
通过深入研究 React 源代码并设置一些断点,我发现通过保存并重用 createElement 结果(const fooOnce = <Foo/>;
)你每次都会有效地使用完全相同的 props 对象,而每次渲染中调用 createElement 都会创建一个新的 props 对象。
目前,这确实会产生影响,因为以下条件function beginWork
来自纤维引擎:if (oldProps !== newProps || hasLegacyContextChanged())
当 props 对象具有相同的标识时,react 立即认为该元素没有任何工作可做(甚至不调用 render)。
对我来说,这似乎很有可能继续工作,但当然不能保证这种优化将始终与这种确切的行为保持一致。
我所指的代码在这里:https://github.com/facebook/react/blob/c7398f33966c4fedcba2c48e915b379e8f334607/packages/react-reconciler/src/ReactFiberBeginWork.js#L2119 https://github.com/facebook/react/blob/c7398f33966c4fedcba2c48e915b379e8f334607/packages/react-reconciler/src/ReactFiberBeginWork.js#L2119
当你只使用普通的时候,你最终会调用 render,并且由于输出不同,它会更新 DOM。
当你使用 React.memo 时,道具会not具有相同的身份,但随后 React 会进入 memo 组件 case (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#L2377)
并做一个shallowEquals比较(https://github.com/facebook/react/blob/c7398f33966c4fedcba2c48e915b379e8f334607/packages/react-reconciler/src/ReactFiberBeginWork.js#L487 https://github.com/facebook/react/blob/c7398f33966c4fedcba2c48e915b379e8f334607/packages/react-reconciler/src/ReactFiberBeginWork.js#L487)
是否有理由不以这种方式重用元素以防止组件更新?
这可以改变,所以我不会在生产代码中使用它。
除此之外,我会避免这种情况,因为组件是否更新的决定超出了组件本身,因为现在要使用它,您需要更改消费者代码,而不是仅仅更改组件上的代码或向其添加包装器。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)