為什麼我無法使用 setState 重置數組?
P粉714890053
P粉714890053 2023-09-02 23:44:06
0
2
573
<p>在我的相機組件中,我想每 3 張照片將照片上傳到儲存桶。我在 React 中使用狀態將圖像 blob 保存到數組中。前 3 張照片一切正常,但之後,我無法將陣列重置為空,並且看似隨機數量的照片被上傳到我的儲存桶中。 </p> <pre class="brush:js;toolbar:false;"> let [blobs, setBlobs] = useState([]); const capturePhoto = async () => { const photo = await camera.current.takePhoto(); fetch(photo.path) .then(res => { setBlobs([...blobs, res._bodyBlob]); console.log('blobs', blobs.length, blobs); }) .catch(err => { console.log('err', err); }); checkLength(); }; const checkLength = async () => { if (blobs.length >= 2) { // upload files to a folder with the current date in a firebase cloud bucket const datestring = new Date().toLocaleString('de-DE'); blobs.forEach((blob, i) => { uploadFile(blob, datestring '/' (i 1) '.jpg'); }); // reset state setBlobs([]); sendNotification('Photos uploaded'); toggleDialog(); } }; </pre> <p>我透過控制台記錄了我的數組,而且大小只會增加。另外,它從零開始控制台日誌記錄,儘管我已經添加了一個元素,這可能是因為 <code>setState()</code> 是異步的。 我試圖通過將其包裝在承諾中來等待重置,但遺憾的是這也不起作用。 一旦有 3 個 Blob,如何將其上傳到雲端並在之後重置清單? </p>
P粉714890053
P粉714890053

全部回覆(2)
P粉439804514

因此,這確實取決於程式碼的執行方式,特別是 setState 的非同步性質,因此您可以使用 setState 的回呼形式。這是一個例子:

setBlobs(prevBlobs => [...prevBlobs, res._bodyBlob]);

這是包含其餘程式碼的完整範例:

const capturePhoto = async () => {
  const photo = await camera.current.takePhoto();
  fetch(photo.path)
    .then(res => {
      setBlobs(prevBlobs => [...prevBlobs, res._bodyBlob]);
      console.log('blobs', blobs.length, blobs);
    })
    .catch(err => {
      console.log('err', err);
    });
  checkLength();
};

const checkLength = async () => {
  if (blobs.length >= 2) {
    // upload files to a folder with the current date in a firebase cloud bucket
    const datestring = new Date().toLocaleString('de-DE');
    blobs.forEach((blob, i) => {
      uploadFile(blob, datestring + '/' + (i + 1) + '.jpg');
    });
    // reset state
    setBlobs([]);
    sendNotification('Photos uploaded');
    toggleDialog();
  }
};
P粉775723722

看起來像三件事:

  1. 不等待提取調用,在提取完成之前調用 checkLength
  2. 在下次渲染之前,您不會獲得 setState 的新值。這是 React 的基本想法(是否是個好主意還有待商榷),狀態值在渲染期間是不可變的。 setState 只是給出下一個渲染將使用的下一個不可變狀態。
  3. setState依賴先前的狀態時,您應該將回呼傳遞給setState,而不是直接使用目前值。舉個例子,假設你有一個空數組,你呼叫 fetch 一次,然後在第一個數組完成之前再次呼叫 fetch 。在執行 ...blob 時,這兩個 setState 呼叫都會引用空數組。透過傳遞回調,setState 取得作為參數傳入的最新值。更多資訊: https://react.dev/reference/react/Component#setstate

最簡單的解決方案是將陣列作為參數傳遞給 setState 回呼內的 checkLength

這是問題中的 .then()

  const capturePhoto = async () => {
    const photo = await camera.current.takePhoto();
    fetch(photo.path)
      .then(res => {
        setBlobs(prev => {
          const newBlobs = [...prev, res._bodyBlob];
          console.log('blobs', newBlobs.length, newBlobs);
          checkLength(newBlobs);
          return newBlobs;
        });
      })
      .catch(err => {
        console.log('err', err);
      });
  };

這是async await

#
  const capturePhoto = async () => {
    const photo = await camera.current.takePhoto();
    const res = await fetch(photo.path).catch(console.error);
    if (!res) return;
    setBlobs(prev => {
      const newBlobs = [...prev, res._bodyBlob];
      console.log('blobs', newBlobs.length, newBlobs);
      checkLength(newBlobs);
      return newBlobs;
    });
  };

檢查長度

  const checkLength = async (newBlobs) => {
    if (newBlobs.length >= 2) {
      // upload files to a folder with the current date in a firebase cloud bucket
      const datestring = new Date().toLocaleString('de-DE');
      newBlobs.forEach((blob, i) => {
        uploadFile(blob, datestring + '/' + (i + 1) + '.jpg');
      });
      // reset state
      setBlobs([]);
      sendNotification('Photos uploaded');
      toggleDialog();
    }
  };
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!