繁体   English   中英

reactJS useState hook 实际值在异步承诺中已过时

[英]reactJS useState hook actual value is out dated in async promises

In my react function component I send multiple server request and update a state hook value through asynchronous promises by appending server results to state most recent value, but once promise is created, value of state hook is not updated within the running promise, so if another promise 更新 state 值,其他正在运行的 Promise 没有得到通知,因此他们使用旧版本的 state 进行进一步的 Z69ED39E2EA931586B6A985A6942EF573EZ 更新。

下面的代码是我的组件的简化版本,我希望在每个 promise 的第 19 行控制台日志中看到相同(和最新)的值,同时运行多个承诺并且 state 得到更新。

function App() {

  const [myArray, setMyArray] = useState([0,1,2])
  const sleep = (ms:number) => {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
  const updateArray = () => {
    setMyArray([...myArray, myArray.length])
  }
  const firePromise = () => {
    new Promise(async (resolve) => {
      const timeStamp = new Date().getTime()
      let repeatTime = 0
      while(repeatTime < 12){
        console.log("array: ", myArray, "promiseIdenifier: ", timeStamp);
        repeatTime += 1
        await sleep(1000)
      }
      resolve({timeStamp, myArray})
    }).then(val => {
      console.log("resolved: ", val);
      
    }).catch(err => {
      console.log("rejected: ", err);
      
    })
  }
  return (
    <div className="App">
      <button onClick={firePromise}>new promise</button>
      <button onClick={updateArray}>updateArray</button>
    </div>
  );
}

export default App;
  

一旦 React 组件被渲染,就可以假设组件的当前“状态”像快照一样存在。

在创建 firePromise 时,console.log 中的“myArray”是“myArray”。 所以保留第一个值是正确的。 (每次渲染组件时,都会创建一个新的 firePromise。)

有一种方法。 第一种是使用 ref,第二种是使用 setState。

第一的

function App() {
  const myArray = useRef<Array<number>>([0, 1, 2]);
  const sleep = (ms: number) => {
    return new Promise((resolve) => setTimeout(resolve, ms));
  };
  const updateArray = () => {
    myArray.current.push(myArray.current.length);
  };
  const firePromise = () => {
    new Promise(async (resolve) => {
      const timeStamp = new Date().getTime();
      let repeatTime = 0;
      while (repeatTime < 12) {
        console.log(
          "array: ",
          myArray.current,
          "promiseIdenifier: ",
          timeStamp
        );
        repeatTime += 1;
        await sleep(1000);
      }
      resolve({ timeStamp, myArray: myArray.current });
    })
      .then((val) => {
        console.log("resolved: ", val);
      })
      .catch((err) => {
        console.log("rejected: ", err);
      });
  };
  return (
    <div className="App">
      <button onClick={firePromise}>new promise</button>
      <button onClick={updateArray}>updateArray</button>
    </div>
  );
}

export default App;

第二

function App() {
  const [myArray, setMyArray] = useState([0, 1, 2]);
  const sleep = (ms: number) => {
    return new Promise((resolve) => setTimeout(resolve, ms));
  };
  const updateArray = () => {
    setMyArray([...myArray, myArray.length]);
  };
  const firePromise = () => {
    new Promise(async (resolve) => {
      const timeStamp = new Date().getTime();
      let repeatTime = 0;
      while (repeatTime < 12) {
        setMyArray((prevMyArray) => {
          console.log("array: ", prevMyArray, "promiseIdenifier: ", timeStamp);
          return prevMyArray;
        });
        repeatTime += 1;
        await sleep(1000);
      }
      setMyArray((prevMyArray) => {
        resolve({ timeStamp, prevMyArray });
        return prevMyArray;
      });
    })
      .then((val) => {
        console.log("resolved: ", val);
      })
      .catch((err) => {
        console.log("rejected: ", err);
      });
  };
  return (
    <div className="App">
      <button onClick={firePromise}>new promise</button>
      <button onClick={updateArray}>updateArray</button>
    </div>
  );
}

export default App;

将回调传递给 setState function 时,当前 state 作为第一个参数传递。 这是使用它的快捷方式。

建议使用 state 值变化时视图应该变化的值。 更改“myArray”不会影响视图,因此使用 ref 是正确的方法。

阅读: https://iqkui.com/a-complete-guide-to-useeffect/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM