reactjs - 重用 React 元素可防止组件更新
问题描述
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)。
这对我来说似乎很有可能继续工作,但当然不能保证这种优化将始终与这种确切的行为一致。
当您只使用正常时,您最终会调用渲染,并且由于输出不同,它将更新 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)
是否有理由不以这种方式重用元素来防止组件更新?
这可以改变,所以我不会在生产代码中使用它。
除了这个原因,我会避免这种情况,因为组件是否更新的决定来自组件本身,因为现在要使用它,您需要更改使用者代码,而不是仅仅更改组件上的代码或向其添加包装器。
推荐阅读
- c++ - 如何在 Unreal Engine 4 中使用 C++ 在运行时从 3d 文件(如 .fbx)的二进制数据生成网格?
- ffmpeg - m3u8 hls 使用 ffmpeg 一步一步流到 wav
- r - R:使用 Torch 进行优化 - optimizer$step() 抛出此错误
- angular - 自定义 NgRx 操作似乎不适用于角度 11
- php - 如果自定义字段值大于 x 回显图像?
- r - 使用 pivot_wider 从没有 values_from 列的逗号分隔向量创建唯一列
- java - Spring Web客户端返回异常“bodyType = [responseObject]不支持内容类型'application / json'
- javascript - 尝试将我的 javascript 代码导入一个 js 文件并从中创建一个 html 页面
- ios - 在滚动时更改后退按钮的色调颜色
- python - 将绘图转换为 1 和 0 的数组