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

在我的反应函数组件中,我发送多个服务器请求并通过异步承诺更新状态挂钩值,方法是将服务器结果附加到状态最新值,但是一旦创建承诺,状态挂钩的值不会在运行的承诺内更新,因此如果另一个Promise 更新状态值,其他正在运行的 Promise 不会收到通知,因此它们使用旧版本的状态来进行进一步的状态更新。

下面的代码是我的组件的简化版本,我希望在多个 Promise 运行且状态更新时,从每个 Promise 的第 19 行控制台日志中看到相同(且最新)的值。

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;

  


绝地无双
浏览 116回答 1
1回答

桃花长相依

一旦 React 组件被渲染,就可以假设组件的当前“状态”像快照一样存在。console.log 中的“myArray”是创建 firePromise 时的“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 函数时,当前状态将作为第一个参数传递。这是使用这个的快捷方式。建议使用当值改变时视图应该改变的值作为状态。更改“myArray”不会影响视图,因此使用 ref 是正确的方法。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript