P粉4398045142023-09-03 16:06:45
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粉7757237222023-09-03 16:04:09
Looks like three things:
checkLength
before the fetch is complete. setState
until the next render. This is the basic idea of React (whether it's a good idea is debatable), state values are immutable during rendering. setState
Just gives the next immutable state that will be used by the next render. setState
depends on a previous state, you should pass a callback to setState
rather 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. Both setState
calls will reference empty arrays when executing ...blob
. By passing a callback, setState
gets 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 to checkLength
inside the setState
callback.
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 isasync
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; }); };
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(); } };