【问题标题】:reactJS useState hook actual value is out dated in async promisesreactJS useState hook 实际值在异步承诺中已过时
【发布时间】:2020-12-10 09:46:47
【问题描述】:

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

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

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;
  

【问题讨论】:

  • 在这种情况下,你最好使用 refs 而不是 state,试试 useRef
  • 很棒的提示,你绝对救了我一整天的兄弟 =) @Konstantin

标签: javascript reactjs promise


【解决方案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 函数时,当前状态作为第一个参数传递。这是使用 this 的快捷方式。

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

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

【讨论】:

  • 我使用了useRef 解决方案,效果很好
猜你喜欢
  • 2021-08-17
  • 1970-01-01
  • 2022-11-15
  • 1970-01-01
  • 2021-03-30
  • 1970-01-01
  • 2020-01-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多