Why can't I reset the array using setState?
P粉714890053
P粉714890053 2023-09-02 23:44:06
0
2
530

In my camera component I want to upload photos to a bucket every 3rd photo. I'm using state in React to save an image blob into an array. Everything works fine for the first 3 photos, but after that, I can't reset the array to empty and a seemingly random number of photos get uploaded to my bucket.

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

I logged my array via console and the size only increased. Also, it starts console logging from scratch even though I've added an element, probably because setState() is asynchronous. I tried to wait for the reset by wrapping it in a promise, but unfortunately that didn't work either. Once there are 3 blobs, how do I upload them to the cloud and reset the list afterwards?

P粉714890053
P粉714890053

reply all (2)
P粉439804514

So it really depends on how the code is executed, specifically the asynchronous nature of setState so you can use the callback form of setState. Here is an example:

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

Here is the complete example with the rest of the 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

    Looks like three things:

    1. Do not wait for the fetch call, callcheckLengthbefore the fetch is complete.
    2. You won't get a new value forsetStateuntil the next render. This is the basic idea of React (whether it's a good idea is debatable), state values are immutable during rendering.setStateJust gives the next immutable state that will be used by the next render.
    3. WhensetStatedepends on a previous state, you should pass a callback tosetStaterather than using the current value directly. For example, let's say you have an empty array, you call fetch once, and then call fetch again before the first array is completed. BothsetStatecalls will reference empty arrays when executing...blob. By passing a callback,setStategets the latest value passed in as a parameter. More information:https://react.dev/reference/react/Component#setstate

    The simplest solution is to pass the array as a parameter tocheckLengthinside thesetStatecallback.

    This is.then()in the 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); }); };

    This isasyncawait

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

    Check length

    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(); } };
      Latest Downloads
      More>
      Web Effects
      Website Source Code
      Website Materials
      Front End Template
      About us Disclaimer Sitemap
      php.cn:Public welfare online PHP training,Help PHP learners grow quickly!