Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/399.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript React useState钩子返回旧的状态值,尽管它正在更新_Javascript_Reactjs_Asynchronous_React Hooks - Fatal编程技术网

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

我想:

  • 将图像上载到浏览器中(我使用React Dropzone执行此操作。下面的My
    uploadImage
    函数将文件的一部分拖放到Dropzone中。)
  • 使用FileReader API将图像作为实际图像读取
  • 使用React钩子将图像文件和图像元数据保存到状态
  • 进行API调用,将此映像推送到服务器
  • 我试图确认我在步骤4中有图像,但无法通过控制台消息确认。尽管日志消息显示状态已被更新,但我还是坚持使用原始状态值

    我已经尝试过在每件事中添加额外的异步,并且我已经在承诺中包装了一些东西。我可以确认
    readImage
    功能正常。我可以确认运行顺序是saveImage中的
    readImage
    saveImage
    setGraphic
    ,然后登录console.log
    uploadImage
    ,它应该有更新的值,但没有

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