尽管useState挂钩已更新,但它仍返回旧状态值

时间:2019-05-25 11:28:00

标签: javascript reactjs asynchronous react-hooks

我要:

  1. 将图像上传到浏览器(我使用React Dropzone做到这一点。我下面的uploadImage函数将文件的onDrop运行到Dropzone中。)
  2. 使用FileReader API将图像读取为实际图像。
  3. 使用React Hooks将图像文件和图像元数据保存到状态。
  4. 进行API调用,将该图像推送到服务器。

我正在尝试确认我在第4步中拥有该映像,但是我无法通过控制台消息来确认。尽管日志消息显示状态已经更新,但我还是会停留在原始状态值上。

我尝试为所有内容添加额外的异步,并且将内容包装在promises中。我可以确认readImage函数正常。我可以确认运行顺序是saveImage中的readImagesaveImagesetGraphic,然后是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> )
}

这是我奇怪的控制台序列:

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}

我的理论

useState挂钩正在执行一些时髦的操作。 进程在启动时就复制该值,而不是在每次读取console.log时都读取它,因此uploadImage函数在该进程的生存期内获取useState钩子的原始值。

1 个答案:

答案 0 :(得分:0)

如果我们将所有那些React Magic简化为:p

  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);
  });

如您所见,setCount不会直接更改状态(count)。实际上,它根本不会更改本地count变量。因此,“之前”和“之后”将始终记录相同(只要您不直接突变counter即可。)

将延迟调用setCount(并在React中进行批处理),然后调用将整个组件函数传递给新计数。

因此,尝试await setState调用是没有意义的,在状态之前和之后记录状态也是没有意义的(因为状态之间不会发生变化)。将其记录在组件中一次,如果您设置状态,则整个组件将再次执行,并且日志记录将记录新状态。

相关问题