React 文档指出:
如果将状态变量设置为当前值,即使没有
,React 也会跳过重新渲染组件。您可能仍然会看到您的组件函数被额外调用一次,但结果将被丢弃。memo
[链接]
我认为这意味着,在如下所示的组件中:
const Component = memo(function () {
const [foo, setFoo] = useState('x');
setFoo(foo); // no-op?
return null;
});
setFoo(foo)
语句实际上不会做任何事情,因为它显然将foo
设置为它已有的值,所以React不会触发新的渲染。
但是,当我尝试这个(在 Create React App 项目中)时,我发现它会导致此错误:
错误:重新渲染次数过多。 React 限制渲染次数以防止无限循环。
在我的测试中,我发现无论有没有
<React.StrictMode>
,在开发模式(npm start
)和生产模式(npm run build
)下,无论有还是没有memo
,都会发生同样的情况setFoo(foo)
并与 setFoo(val => val)
。这发生在一个新的 Create React App 项目中,所以它对我的设置来说不能太具体。
由于文档提到“您可能仍然会看到您的组件函数被额外调用一次”(在这种情况下,额外时间将重新调用
setFoo
),我认为也许这只是错误消息是有点错误,应该说“对组件功能的重复调用太多”而不是“重新渲染太多”;但不,我确认,如果我跟踪调用次数并最终停止重新调用 setFoo
,React 会渲染从 last 调用组件函数返回的内容,而不是从 first 调用返回的内容,所以即使医生所说的“结果将被丢弃”似乎也不是真的。
我错过了什么?文档有错吗?
凭直觉,我测试了如果我写
setTimeout(() => setFoo(foo), 10)
而不是 setFoo(foo)
会发生什么——这样状态是在 10 毫秒延迟后设置的,而不是在组件函数实际运行时设置的——在这种情况下,它做到了 not 触发新的渲染。 (事实上,它甚至没有额外调用组件函数。)
所以文档中的说法似乎是:
如果将状态变量设置为当前值,即使没有
,React 也会跳过重新渲染组件。您可能仍然会看到您的组件函数被额外调用一次,但结果将被丢弃。memo
如果状态变量在调用组件函数期间被设置,则不适用;在这种情况下,即使状态变量被设置为其当前值,React 也一定会丢弃正在进行的渲染并触发新的调用。
(对于是否应该改变这种行为,我将保留评论。)
文档中在
useState
的特殊用例下提到了这一点:存储以前渲染的信息。
允许在组件渲染期间调用
setState
函数来立即以新状态重新渲染组件。这可用于根据当前状态和先前状态之间的差异显示信息,而不需要较低的性能useEffect
。
请参阅文档中的此警告:
请注意,如果在渲染时调用 set 函数,则它必须位于类似
的条件内,并且条件内部必须存在类似prevCount !== count
的调用。否则,您的组件将循环重新渲染,直到崩溃。另外,您只能像这样更新当前渲染组件的状态。在渲染过程中调用另一个组件的setPrevCount(count)
函数是错误的。set