await React setState的方法

await React setState的方法

更新於 發佈於 閱讀時間約 5 分鐘

如果有個算法是2秒以上很耗時的長任務,希望在執行長任務前後修改state渲染loading畫面,可能會難以達到預期效果,會看到loading畫面一閃而過。

setLoading(true);
longTask();
setLoading(false);

因為React在setstate後狀態不會馬上改變與渲染,如果後面緊跟一個長任務,長任務會馬上佔用所有資源,直到結束後才改變狀態與渲染。

把setState改非同步的方法

實現的思路是在setState時建立一個Promise,然後useEffect監聽到狀態改變後呼叫這個Promise的resolve方法,直接上程式碼。

const Main = () => {
  const [spinning, setSpinning] = useState(false);

// 防止useEffect取到的spinning和setSpinningAsync裡取到的不同
  const spinningStateRef = useRef(false);
// 儲存Promise的resolve方法
  const spinningResolveRef = useRef(() => {});

  const setSpinningAsync = (isSpinning) => {
// 先呼叫與清空上次的resolve,避免有地方程式被await卡住
    spinningResolveRef.current();
    spinningResolveRef.current = () => {};

    const currentLoadingState = spinningStateRef.current;
    if (isSpinning == currentLoadingState) return;

    return new Promise((resolve) => {
      setSpinning(isSpinning);
// setState後儲存這次Promise的resolve
      spinningResolveRef.current = resolve;
    });
  };

  useEffect(() => {
    const updateSpinningRef = async () => {
// 如果電腦很卡,可以多設些緩衝時間確保畫面已渲染
      await new Promise((resolve) => setTimeout(resolve, 100));
// 確保狀態已改變,畫面已渲染,就呼叫resolve(),讓executWithAsync函式await的程式繼續
      spinningResolveRef.current();
      spinningStateRef.current = spinning;
    };

    updateSpinningRef();
  }, [spinning]);

  const executWithAsync = async () => {
    await setSpinningAsync(true);
    longSyncTask(2000);
    await setSpinningAsync(false);
  };

  return (
    <Spin spinning={spinning}>
      <Button onClick={executWithAsync}>Wait until spinning</Button>
    </Spin>
  );
};

最後附上完整demo: await useState demo

內容總結
React await setStat
4
/5
avatar-img
s_SoNg的沙龍
4會員
11內容數
留言
avatar-img
留言分享你的想法!
s_SoNg的沙龍 的其他內容
在工作上遇到nodejs呼叫執行檔執行失敗問題,最後發現是由於nodejs專案本身有用nssm包成服務,在服務環境的nodejs呼叫的執行檔也執行在服務中,造成程式不會跳出視窗而導致失敗。
準備專案 這邊首先準備一個新的專案,可以參考react官網,完成後參考README.md輸入npm run dev就可以啟動並在瀏覽器看到畫面 準備nssm工具 在google上搜nssm,第一個項目點進去後,找到並下載穩定版,附上下載鏈接 壓縮檔下載完畢後,解壓縮到喜歡的地方,然後進入資料
利用shapecast函式參與過濾的過程
在工作上遇到nodejs呼叫執行檔執行失敗問題,最後發現是由於nodejs專案本身有用nssm包成服務,在服務環境的nodejs呼叫的執行檔也執行在服務中,造成程式不會跳出視窗而導致失敗。
準備專案 這邊首先準備一個新的專案,可以參考react官網,完成後參考README.md輸入npm run dev就可以啟動並在瀏覽器看到畫面 準備nssm工具 在google上搜nssm,第一個項目點進去後,找到並下載穩定版,附上下載鏈接 壓縮檔下載完畢後,解壓縮到喜歡的地方,然後進入資料
利用shapecast函式參與過濾的過程