反应清理功能不清理状态
React cleanup function doesn't clean state
各位专家,
请解释一下,为什么在下面的代码中 属性 的状态不会在 useEffect 清理函数中被清理?
我的组件:
export default function TestComp() {
let { id } = useParams();
const [value, setValue] = useState(null);
console.log('[TestComp] called...');
const cleanup = () => {
console.log('[TestComp] old value', value);
setValue(null);
};
useEffect(() => {
console.log('[TestComp] id changed: ', id);
console.log('[TestComp] value in useEffect', value);
setValue(id);
return () => {
cleanup();
}
}, [id]);
return (<React.Fragment>Test id: {id}</React.Fragment>)
}
控制台输出:
[TestComp] called... TestComp.js:8
[TestComp] old value satellites:MTP TestComp.js:11
[TestComp] id changed: satellites:MTP TestComp.js:16
[TestComp] value in useEffect satellites:FPGA TestComp.js:17
[TestComp] called... 2 TestComp.js:8
[TestComp] old value satellites:FPGA TestComp.js:11
[TestComp] id changed: satellites:FNE TestComp.js:16
[TestComp] value in useEffect satellites:MTP TestComp.js:17
[TestComp] called... TestComp.js:8
我预计,当第二次调用 useEffect 时,value 将被清除并且为 null,但它仍然保持旧值:
value in useEffect satellites:MTP TestComp.js:17
提前致谢。
我认为这是事情发生的顺序问题。
useEffect
将 'capture' 值作为闭包的一部分在调用时作为闭包的一部分,即当调用 TestComp
函数时。当 id 更改时,React 将安排对清理函数的调用,然后调用 effect。但是 TestComp
在调用新效果函数之前不会再次调用。
您可以在日志中看到这一点,因为清理函数中的每个 old value
紧接着是效果函数中的 id changed
。
并且因为调用 TestComp
时的新效果函数 'captures' 值,它不会看到清理函数设置的值。
另请注意,至少从测试中我看到 React 抱怨 value
和 cleanup
不在 useEffect
的依赖项中。
您可能想添加另一个 useEffect
,因为在当前情况下,cleanup
函数将 运行 仅在 卸载 时这对当前的逻辑来说毫无用处。
export default function TestComp() {
let { id } = useParams();
const [value, setValue] = useState(null);
console.log('[TestComp] called...');
useEffect(() => {
console.log('[TestComp] id changed: ', id);
console.log('[TestComp] value in useEffect', value);
setValue(id);
/* v Useless cleanup because the component unmounts anyway,
the `value` state will be cleaned automatically.
return () => {
cleanup();
}
*/
}, [id]);
// ^ Firstly, the `value` changed on id change
// v Secondly, the `value` will be reset on `value` change
useEffect(() => {
console.log('[TestComp] old value', value);
setValue(null);
}, [value]);
return <>Test id: {id}</>;
}
useEffect 中的 Return 函数只是在应用下一个效果之前清除之前的效果。但是您代码中的主要问题是
const cleanup = () => {
console.log('[TestComp] old value', value);
setValue(null); // This is not prefer way to use setValue here.
}
通常,在清理期间我们取消订阅外部 service/subscription 但在这里您正在更改此处没有意义的状态并立即通过 useEffect setValue 获取更新 [= =47=] 并且在 setValue 内部清理调用之后,这也是再次调用 effect 的原因,
在你的 useEffect 中添加 setTimeout 后检查你的代码。
`useEffect(() => {
console.log('[TestComp] id changed: ', id);
console.log('[TestComp]:Effect value in useEffect', value);
setValue(id);
return () => {
setTimeout(()=> cleanup(), 5000)
}
}, [id]);`
可能的解决方案-
在上述情况下,您使用的是 id,将此 属性 提升到父组件并将其作为 属性 传递给 TestComp组件.
当效果 运行 的整个组件重新渲染并且作用域被销毁但所有状态都保持在 useState 钩子的闭包内。
各位专家, 请解释一下,为什么在下面的代码中 属性 的状态不会在 useEffect 清理函数中被清理?
我的组件:
export default function TestComp() {
let { id } = useParams();
const [value, setValue] = useState(null);
console.log('[TestComp] called...');
const cleanup = () => {
console.log('[TestComp] old value', value);
setValue(null);
};
useEffect(() => {
console.log('[TestComp] id changed: ', id);
console.log('[TestComp] value in useEffect', value);
setValue(id);
return () => {
cleanup();
}
}, [id]);
return (<React.Fragment>Test id: {id}</React.Fragment>)
}
控制台输出:
[TestComp] called... TestComp.js:8
[TestComp] old value satellites:MTP TestComp.js:11
[TestComp] id changed: satellites:MTP TestComp.js:16
[TestComp] value in useEffect satellites:FPGA TestComp.js:17
[TestComp] called... 2 TestComp.js:8
[TestComp] old value satellites:FPGA TestComp.js:11
[TestComp] id changed: satellites:FNE TestComp.js:16
[TestComp] value in useEffect satellites:MTP TestComp.js:17
[TestComp] called... TestComp.js:8
我预计,当第二次调用 useEffect 时,value 将被清除并且为 null,但它仍然保持旧值:
value in useEffect satellites:MTP TestComp.js:17
提前致谢。
我认为这是事情发生的顺序问题。
useEffect
将 'capture' 值作为闭包的一部分在调用时作为闭包的一部分,即当调用 TestComp
函数时。当 id 更改时,React 将安排对清理函数的调用,然后调用 effect。但是 TestComp
在调用新效果函数之前不会再次调用。
您可以在日志中看到这一点,因为清理函数中的每个 old value
紧接着是效果函数中的 id changed
。
并且因为调用 TestComp
时的新效果函数 'captures' 值,它不会看到清理函数设置的值。
另请注意,至少从测试中我看到 React 抱怨 value
和 cleanup
不在 useEffect
的依赖项中。
您可能想添加另一个 useEffect
,因为在当前情况下,cleanup
函数将 运行 仅在 卸载 时这对当前的逻辑来说毫无用处。
export default function TestComp() {
let { id } = useParams();
const [value, setValue] = useState(null);
console.log('[TestComp] called...');
useEffect(() => {
console.log('[TestComp] id changed: ', id);
console.log('[TestComp] value in useEffect', value);
setValue(id);
/* v Useless cleanup because the component unmounts anyway,
the `value` state will be cleaned automatically.
return () => {
cleanup();
}
*/
}, [id]);
// ^ Firstly, the `value` changed on id change
// v Secondly, the `value` will be reset on `value` change
useEffect(() => {
console.log('[TestComp] old value', value);
setValue(null);
}, [value]);
return <>Test id: {id}</>;
}
Return 函数只是在应用下一个效果之前清除之前的效果。但是您代码中的主要问题是
const cleanup = () => {
console.log('[TestComp] old value', value);
setValue(null); // This is not prefer way to use setValue here.
}
通常,在清理期间我们取消订阅外部 service/subscription 但在这里您正在更改此处没有意义的状态并立即通过 useEffect setValue 获取更新 [= =47=] 并且在 setValue 内部清理调用之后,这也是再次调用 effect 的原因,
在你的 useEffect 中添加 setTimeout 后检查你的代码。
`useEffect(() => {
console.log('[TestComp] id changed: ', id);
console.log('[TestComp]:Effect value in useEffect', value);
setValue(id);
return () => {
setTimeout(()=> cleanup(), 5000)
}
}, [id]);`
可能的解决方案-
在上述情况下,您使用的是 id,将此 属性 提升到父组件并将其作为 属性 传递给 TestComp组件.
当效果 运行 的整个组件重新渲染并且作用域被销毁但所有状态都保持在 useState 钩子的闭包内。