我正在阅读关于useCallback
和memo
的React文档,如果我必须在下面的示例中同时使用这两个文档,我会有点困惑。
启动器代码:
function ProductPage({ productId, referrer, theme }) {
// ...
return (
<div className={theme}>
<ShippingForm onSubmit={handleSubmit} />
</div>
);
从上面的代码中可以看出,切换theme
属性会使应用程序冻结一段时间,但如果从JSX中删除<ShippingForm />
,则会感觉很快。因此,我们必须优化ShippingForm
组件,因为默认情况下,当组件重新呈现时,React会递归地重新呈现其所有子组件。因此,为了解决这个问题,我们可以告诉ShippingForm
跳过重新渲染,当它的props与上次渲染相同时,通过将其 Package 在memo
中,如下所示:
import { memo } from 'react';
const ShippingForm = memo(function ShippingForm({ onSubmit }) {
// ...
});
但是,如果handleSubmit
函数是一个箭头函数或使用function关键字的常规函数,memo
优化将不起作用,因为在JavaScript中,function () {}
或() => {}
总是创建不同的函数,类似于{}
对象文字总是创建新对象。因此,ShippingForm
prop 将永远不会相同,memo
优化也不会起作用。
下面的代码将不起作用
function ProductPage({ productId, referrer, theme }) {
// Every time the theme changes, this will be a different function...
function handleSubmit(orderDetails) {
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}
return (
<div className={theme}>
{/* ... so ShippingForm's props will never be the same, and it will re-render every time */}
<ShippingForm onSubmit={handleSubmit} />
</div>
);
}
这也不行
function ProductPage({ productId, referrer, theme }) {
// Every time the theme changes, this will be a different function...
const handleSubmit = (orderDetails)=> {
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}
return (
<div className={theme}>
{/* ... so ShippingForm's props will never be the same, and it will re-render every time */}
<ShippingForm onSubmit={handleSubmit} />
</div>
);
}
因此,为了解决这个问题,我们必须使用useCallback
钩子,如下所示。
现在我的问题是,既然我们使用了useCallback
钩子,我们是否仍然通过将memo
Package 在memo
中,来告诉ShippingForm
跳过重新渲染,当它的props与上次渲染相同时?还是没必要?谢谢你帮忙
function ProductPage({ productId, referrer, theme }) {
// Tell React to cache your function between re-renders...
const handleSubmit = useCallback((orderDetails) => {
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}, [productId, referrer]); // ...so as long as these dependencies don't change...
return (
<div className={theme}>
{/* ...ShippingForm will receive the same props and can skip re-rendering */}
<ShippingForm onSubmit={handleSubmit} />
</div>
);
}
2条答案
按热度按时间iswrvxsc1#
是的,你应该两者都用。
P.S.你的问题中有一个小错误:useMemo是一个用于在组件内部存储值的钩子(类似于useCallback,但它保存函数执行的结果)。React.memo几乎是相同的东西,但组件本身。你问的是最后一件事。
rt4zxlrg2#
所有的困惑都来自于你假设一个组件在接收不同的 prop 时呈现。实际上,组件仅在其内部状态更改或其父组件呈现时才呈现。这就是为什么这个没有props的
Child
组件在其父组件渲染时被再次调用的原因:当这种行为有问题时,因为
Child
做了大量的计算,例如,你可以告诉React在memo
的帮助下,只有当它接收到新的props时才渲染它:memo
将比较以前的props和新的props(在渲染Parent
时)。如果相同,则跳过渲染Child
。无论您是否传递任何类似上面的或原始的属性,这都是有效的。然而,如果你传递一个在Parent
的主体中定义的对象或函数,它们会被传递给不同的内存引用,因此我们使用useCallback
来记忆函数,使用useMemo
来记忆对象:因此,您需要两个或其中一个,具体取决于您的用例。