Javascript React useState钩子返回旧的状态值,尽管它正在更新
我想:Javascript React useState钩子返回旧的状态值,尽管它正在更新,javascript,reactjs,asynchronous,react-hooks,Javascript,Reactjs,Asynchronous,React Hooks,我想: 将图像上载到浏览器中(我使用React Dropzone执行此操作。下面的MyuploadImage函数将文件的一部分拖放到Dropzone中。) 使用FileReader API将图像作为实际图像读取 使用React钩子将图像文件和图像元数据保存到状态 进行API调用,将此映像推送到服务器 我试图确认我在步骤4中有图像,但无法通过控制台消息确认。尽管日志消息显示状态已被更新,但我还是坚持使用原始状态值 我已经尝试过在每件事中添加额外的异步,并且我已经在承诺中包装了一些东西。我可以确认r
uploadImage
函数将文件的一部分拖放到Dropzone中。)readImage
功能正常。我可以确认运行顺序是saveImage中的readImage
,saveImage
,setGraphic
,然后登录console.loguploadImage
,它应该有更新的值,但没有
const [graphic, setGraphic] = useState({ ...nullGraphic });
const readImage = async (img) => {
const reader = new FileReader();
return new Promise((resolve, reject) => {
reader.onerror = () => reader.abort();
reader.onabort = () => reject(new DOMException('Problem parsing input file.'));
reader.onload = () => resolve(reader.result);
reader.readAsDataURL(img);
});
};
const saveImage = async (img) => {
const imageRead = await readImage(img);
console.log(imageRead);
await setGraphic({
...graphic,
image: imageRead,
imageName: img.name,
imageType: img.type,
});
};
const uploadImage = async (img) => {
await saveImage(img);
console.log(graphic);
});
render() {
console.log(graphic);
return( <some dom> )
}
我的理论
useState钩子正在做一些时髦的事情。
进程在启动时复制该值,而不是在读取console.log时读取该值,因此
uploadImage
函数在该进程的生命周期内获取useState钩子的原始值。如果我们将所有这些函数简化为:
function withState(initial, fn) {
function setState(updated) {
setTimeout(() => fn(updated, setState), 0);
//...
}
setState(initial);
}
现在我们可以说明发生了什么:
withState(0, (counter, setCount) => {
console.log("before", counter);
if(counter < 10) setCount(counter + 1);
console.log("after", counter);
});
带状态(0,(计数器,设置计数)=>{
控制台日志(“之前”,计数器);
如果(计数器<10)设置计数(计数器+1);
控制台日志(“之后”,计数器);
});
如您所见,setCount
不会直接更改状态(count
)。它实际上根本不会更改本地计数变量。因此,“before”和“after”将始终记录相同的日志(只要您不直接改变计数器)
相反,调用setCount
将被区分(并在React中批处理),然后它将调用传递新计数的整个组件函数
因此,尝试等待
setState调用是没有意义的,在调用前后记录状态也是没有意义的(因为在调用之间状态不会改变)。在一个组件中记录一次,如果您设置状态,整个组件将再次执行,日志将记录新状态。您为什么认为可以等待setGraphic
?我假设它会返回一个承诺。即使没有,我也试着用承诺来包装它,但没有任何改变。我不认为这是问题所在,因为它显然是在按照我希望的顺序更新状态。读取状态是无序的。setState
被批量刷新,这意味着它是异步的,但它不会返回承诺,因此您不能等待它。如果在调用setState
后立即记录下一个状态,则不会记录更新的状态,因为它是异步的。如果使用挂钩,这意味着这是一个功能组件,为什么要使用渲染方法,您是否应该直接返回JSX并在JSX中包含console.log语句?@iqbal125您是对的,没有呈现方法。我正试图构建一个简化版本的组件,我在这一部分搞砸了。你指出了这些错误是有帮助的,但我缺少的是更大的答案。我试图做的事情的广义概念是否可能,而不必将所有内容都放在一个函数中?我也不明白React魔法功能是从哪里来的。你是怎么构造的?
withState(0, (counter, setCount) => {
console.log("before", counter);
if(counter < 10) setCount(counter + 1);
console.log("after", counter);
});