我有一个功能组件,它使用 useState 初始化状态,然后通过输入字段更改此状态。
然后,我有一个 useEffect 挂钩来模拟 componentWillUnmount,以便在组件卸载之前,将当前更新的状态记录到控制台。但是,会记录初始状态而不是当前状态。
这是我正在尝试做的事情的简单表示(这不是我的实际组件):
import React, { useEffect, useState } from 'react';
const Input = () => {
const [text, setText] = useState('aaa');
useEffect(() => {
return () => {
console.log(text);
}
}, [])
const onChange = (e) => {
setText(e.target.value);
};
return (
<div>
<input type="text" value={text} onChange={onChange} />
</div>
)
}
export default Input;
我将状态初始化为“初始”。然后我使用输入字段来更改状态,假设我输入“新文本”。但是,当组件卸载时,控制台会记录“初始”而不是“新文本”。
为什么会出现这种情况?如何在卸载时访问当前更新的状态?
非常感谢!
编辑:
向 useEffect 依赖项数组添加文本并不能解决我的问题,因为在我的现实场景中,我想要做的是根据当前状态触发异步操作,并且每次都这样做效率不高。 “文本”状态发生变化。
我正在寻找一种方法,仅在组件卸载之前获取当前状态。
您已经有效地记住了初始状态值,因此当组件卸载时,那个值就是返回的函数包含在其范围内的值。
清理功能在组件从 UI 中删除之前运行 以防止内存泄漏。此外,如果一个组件呈现多个 次(正如他们通常所做的那样),先前的效果会在之前被清除 执行下一个效果。在我们的例子中,这意味着一个新的 每次更新时都会创建订阅。为了避免触发效果 每次更新,请参阅下一节。
为了在调用清理函数时获得最新状态,您需要在依赖项数组中包含
text
,以便更新函数。
如果传递一个空数组 (
),则效果内的 props 和状态 总是有它们的初始值。同时将[]
作为第二个 论点更接近熟悉的[]
并且componentDidMount
心理模型,通常有更好的解决方案 以避免过于频繁地重新运行效果。componentWillUnmount
这意味着返回的“清理”函数仍然只访问前一个渲染周期的状态和道具。
编辑
返回一个可变的 ref 对象,其useRef
属性为 初始化为传递的参数 (.current
)。返回的对象 将在组件的整个生命周期中持续存在。initialValue
...
它可以方便地保留任何可变值,类似于在类中使用实例字段的方式。
使用 ref 将允许您缓存可以在清理函数中访问的当前
text
引用。
/编辑
组件
import React, { useEffect, useRef, useState } from 'react';
const Input = () => {
const [text, setText] = useState('aaa');
// #1 ref to cache current text value
const textRef = useRef(null);
// #2 cache current text value
useEffect(() => {
textRef.current = text;
}, [text]);
useEffect(() => {
console.log("Mounted", text);
// #3 access ref to get current text value in cleanup
return () => console.log("Unmounted", text, "textRef", textRef.current);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
console.log("current text", text);
return () => {
console.log("previous text", text);
}
}, [text])
const onChange = (e) => {
setText(e.target.value);
};
return (
<div>
<input type="text" value={text} onChange={onChange} />
</div>
)
}
export default Input;
通过返回的清理函数中的 console.log,您会注意到输入中的每次更改都会将之前的状态记录到控制台。
在此演示中,我在效果中记录了当前状态,并在清理函数中记录了之前的状态。请注意,清理函数首先在下一个渲染周期的当前日志之前记录。