[英]React useState hook returns old state value despite it being updated
I want to: 我想要:
uploadImage
function below runs onDrop of file into Dropzone.) uploadImage
函数将onDrop of file运行到Dropzone。) I am trying to confirm that I have the image at step 4, but I cannot confirm that via my console messages. 我试图确认我在步骤4中有图像,但我无法通过我的控制台消息确认。 I'm somehow stuck with the original state values despite log messages showing the state has already been updated.
尽管日志消息显示状态已经更新,但我仍然坚持原始状态值。
I've tried adding extra asyncs to everything, and I've wrapped stuff in promises. 我已经尝试过为所有东西添加额外的asyncs,并且我已经在promises中包装了东西。 I can confirm the
readImage
function is fine. 我可以确认
readImage
函数没问题。 I can confirm the run sequence is readImage
, saveImage
, setGraphic
within saveImage, and then the console.log in uploadImage
which should have the updated values but doesn't. 我可以确认运行顺序是
readImage
, saveImage
, setGraphic
,然后是uploadImage
中的console.log,它应该具有更新的值但不具有更新的值。
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> )
}
this is my strange console sequence: 这是我奇怪的控制台序列:
Form.js:112 starting saveImage
Form.js:95 (snipped value of imageRead)
Form.js:237 {snipped updated values of graphic}
Form.js:114 done with saveImage
Form.js:116 {snipped original values of graphic}
My Theory 我的理论
The useState hook is doing something funky. useState钩子正在做一些时髦的事情。 The process copies the value when it starts instead of reading it whenever the console.log is being read, so the
uploadImage
function gets the original values of the useState hook for the lifetime of that process. 该进程在启动时复制值,而不是在读取console.log时读取它,因此
uploadImage
函数在该进程的生命周期内获取useState挂钩的原始值。
It might become clear why this would not work if we would simplify all those React magic into : 如果我们将所有那些React魔法简化为以下内容,可能会清楚为什么这不起作用:
function withState(initial, fn) {
function setState(updated) {
setTimeout(() => fn(updated, setState), 0);
//...
}
setState(initial);
}
Now we can illustrate what happens: 现在我们可以说明发生了什么:
withState(0, (counter, setCount) => {
console.log("before", counter);
if(counter < 10) setCount(counter + 1);
console.log("after", counter);
});
As you can see, setCount
will not change the state ( count
) directly. 如您所见,
setCount
不会直接更改状态( count
)。 It will actually not change the local count
variable at all. 实际上它根本不会改变本地
count
变量。 Therefore "before" and "after" will always log the same (as long as you don't mutate counter
directly). 因此“之前”和“之后”将始终记录相同(只要您不直接改变
counter
)。
Instead calling setCount
will be deffered (and batched in React), and then it will recall the whole component function passing in the new count. 而是调用
setCount
将被保护(并在React中进行批处理),然后它将调用传递新计数的整个组件函数。
Therefore it makes no sense trying to await
the setState call, also it makes no sense to log the state before and after it (as it won't change inbetween). 因此,尝试
await
setState调用没有任何意义,也没有必要记录它之前和之后的状态(因为它不会在中间变化)。 Log it once in a component, if you set the state the whole component executes again and the logging will log the new state. 在组件中记录一次,如果设置状态,则整个组件再次执行,日志记录将记录新状态。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.