Pourquoi ne puis-je pas réinitialiser le tableau à l'aide de setState ?
P粉714890053
P粉714890053 2023-09-02 23:44:06
0
2
594
<p>Dans le composant de mon appareil photo, je souhaite télécharger des photos dans un compartiment toutes les trois photos. J'utilise state dans React pour enregistrer une image blob dans un tableau. Tout fonctionne bien pour les 3 premières photos, mais après cela, je ne peux pas réinitialiser le tableau pour qu'il soit vide et un nombre apparemment aléatoire de photos est téléchargé dans mon compartiment. </p> <pre class="brush:js;toolbar:false;"> let [blobs, setBlobs] = useState([]); const capturePhoto = async () => const photo = attendre camera.current.takePhoto(); récupérer (photo.chemin) .then(res => { setBlobs([...blobs, res._bodyBlob]); console.log('blobs', blobs.length, blobs); }) .catch(erreur => { console.log('erreur', erreur); }); checkLength(); } ; const checkLength = async () => if (blobs.length >= 2) { // télécharge des fichiers dans un dossier avec la date actuelle dans un bucket cloud Firebase const datestring = new Date().toLocaleString('de-DE'); blobs.forEach((blob, i) => { uploadFile(blob, datestring + '/' + (i + 1) + '.jpg'); }); // réinitialiser l'état setBlobs([]); sendNotification('Photos téléchargées'); basculeDialog(); } } ; ≪/pré> <p>J'ai connecté ma baie via la console et la taille n'a fait qu'augmenter. En outre, il démarre la journalisation de la console à partir de zéro même si j'ai ajouté un élément, probablement parce que <code>setState()</code> J'ai essayé d'attendre la réinitialisation en l'enveloppant dans une promesse, mais malheureusement cela n'a pas fonctionné non plus. Une fois qu’il y a 3 blobs, comment puis-je les télécharger sur le cloud et réinitialiser la liste par la suite ? </p>
P粉714890053
P粉714890053

répondre à tous(2)
P粉439804514

Cela dépend donc vraiment de la façon dont le code est exécuté, en particulier de la nature asynchrone de setState afin que vous puissiez utiliser le formulaire de rappel de setState . Voici un exemple :

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

Voici l'exemple complet avec le reste du code :

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

Cela ressemble à trois choses :

  1. N'attend pas l'appel de récupération, appelle checkLength avant que la récupération ne soit terminée.
  2. Vous n'obtenez pas setState 的新值。这是 React 的基本思想(是否是个好主意还有待商榷),状态值在渲染期间是不可变的。 setState avant le prochain rendu, juste le prochain état immuable qui sera utilisé par le prochain rendu.
  3. QuandsetState依赖于先前的状态时,您应该将回调传递给setState,而不是直接使用当前值。举个例子,假设你有一个空数组,你调用 fetch 一次,然后在第一个数组完成之前再次调用 fetch 。在执行 ...blob 时,这两个 setState 调用都会引用空数组。通过传递回调,setState Obtenez la dernière valeur transmise en tant que paramètre. Plus d'informations : https://react.dev/reference/react/Component#setstate

La solution la plus simple est de passer le tableau comme argument à setState 回调内的 checkLength dans le rappel setState.

Voici le .then() en question :

  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);
      });
  };

C'estasync 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();
    }
  };
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal