另一个React 18严格模式的问题。我知道React会两次调用render和effect函数,以突出即将推出的特性的潜在内存泄漏。我还不明白的是如何正确处理这个问题。我的问题是,我不能正确卸载第一个渲染结果,因为两次useEffect调用是在第二个渲染的状态下执行的。下面是一个示例来展示我的意思。
const ref = useRef(9);
const id = useId();
console.log('@@ initial id', id);
console.log('@@ initial ref', ref.current);
ref.current = Math.random();
console.log('@@ random ref', ref.current);
useEffect(() => {
console.log('@@ effect id', id);
console.log('@@ effect ref', ref.current);
return () => {
console.log('@@ unmount id', id);
console.log('@@ unmount ref', ref.current);
};
});
下面是日志输出
@@ initial id :r0:
@@ initial ref 9
@@ random ref 0.26890444169781214
@@ initial id :r1:
@@ initial ref 9
@@ random ref 0.7330565878991766
@@ effect id :r1: <<--- first effect doesn't use data of first render cycle
@@ effect ref 0.7330565878991766
@@ unmount id :r1:
@@ unmount ref 0.7330565878991766
@@ effect id :r1:
@@ effect ref 0.7330565878991766
正如您所看到的,第一个渲染周期的状态没有useEffect调用,第二个渲染周期也没有为您提供第一个渲染周期的ref(它再次初始化为9,而不是0.26890444169781214)。此外,useId挂接返回两个不同的id,其中第二个Id也保留在后续的渲染周期中。这是一个错误还是预期行为?如果是预期行为,是否有方法修复?
1条答案
按热度按时间gwbalxhn1#
在React 18的
StrictMode
之前,你的组件只会挂载一次。但是现在,它们会挂载,卸载,然后重新挂载。所以不仅仅是效果运行了两次--你的整个组件都渲染了两次。这意味着你的状态被重新初始化,你的引用也被重新初始化。显然,你的效果也会运行两倍。
关于运行两次的效果,您需要正确清理
async
效果-任何异步执行某些操作的效果,如从服务器获取数据、添加事件侦听器等。并非所有效果都需要清理。此外,特效在开发中应该运行两次(在生产中只运行一次)。有些人试图阻止特效运行两次,但这是不对的。如果你正确地清理了一个特效,它在生产中运行一次或在开发中运行两次应该没有区别。
此外,useId钩子返回两个不同的id,其中第二个Id也在以后的渲染周期中保留。这是一个bug还是预期的行为?如果是预期的,有什么方法可以解决这个问题吗?第二个值将是使用的值。它不是bug,你可以继续使用它作为“true”值。
您可以在
StrictMode
here上了解更多信息。编辑:检测卸载。