React 18 StrictMode first useEffect错误状态



另一个React 18严格模式问题。我知道React将调用渲染和效果函数两次,以突出潜在的内存泄漏与即将到来的特性。我还不明白的是如何正确地处理它。我的问题是,我不能正确卸载第一个渲染结果,因为两个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也保留在进一步的渲染周期中。这是错误还是预期行为?如果是预期的,有办法解决这个问题吗?

在React 18的StrictMode之前,你的组件只能挂载一次。但现在,他们装上,卸下,然后再装上。所以不仅仅是效果会被运行两次,整个组件也会被渲染两次。

这意味着你的状态被重新初始化,你的引用也被重新初始化。显然,你的效果也会运行两次。

关于运行两次的效果,您需要正确清理async效果-任何异步执行的效果,如从服务器获取数据,添加事件侦听器等。并不是所有的效果都需要清理。

同样,这些效果在开发中要运行两次(它们在生产中只运行一次)。有些人试图防止效果运行两次,但这是不对的。如果您正确地清除了一个效果,那么无论它在生产环境中运行一次还是在开发环境中运行两次,它的执行应该没有区别。

useId钩子返回两个不同的Id,其中保留第二个Id也在进一步的渲染周期。这是错误还是预期行为?如果这是预期的,有办法解决这个问题吗?第二个值将是使用的值。这不是一个bug,你可以继续使用它作为"true"。价值。

你可以在这里阅读更多关于StrictMode的信息。

编辑:检测卸载

// Create a ref to track unmount
const hasUnmounted = useRef(false)
useEffect(() => {
return () => {
// Set ref value to true in cleanup. This will run when the component is unmounted. If this is true, your component has unmounted OR the effect has run at least once
hasUnmounted.current = true;
}
}, [])

相关内容

最新更新