{React Native} Async \ Await некорректно работает с setSate - PullRequest
2 голосов
/ 06 мая 2020

Может ли кто-нибудь помочь мне понять, что я делаю неправильно? Рассмотрим этот простой код

 var images = []; 
 const [funImage, setFunImage] = useState([]);


//Some function that does this below
firebase.firestore().collection('PostedFunActivities').where("location", "==" , place).get().then((querySnapshot) =>{
        querySnapshot.forEach(async(doc) =>{ 
            const ref = firebase.storage().ref('images/'+ doc.data().image)
            const result = await ref.getDownloadURL();
            images.push(result);                                                                   
           })
           setFunImage(images);
       });

. Я не понимаю, почему setFunImage(images); выполняется до того, как images.push(result); завершится до pu sh всех результатов в массиве. Я думал, что await заблокирует оставшуюся часть кода под ним. В основном концепция, лежащая в основе того, что я пытаюсь сделать, заключается в том, чтобы все мои результаты были отправлены на images, а ЗАТЕМ вызовут setFunImage(images);.

Как я могу этого добиться? Возможно ли это вообще?

EDIT

Я изменил свой код в надежде найти решение этой проблемы, и вот где я дошел до сих пор:

firebase.firestore().collection('PostedFunActivities').where("location", "==" , place).get().then((querySnapshot) => {
   querySnapshot.forEach(async(doc) => {
     const ref = firebase.storage().ref('images/' + doc.data().image)
     const result = await ref.getDownloadURL();
     images.push(result);
     setFunImage(...funImage,images);
     }) 
});

Интересно, что когда эта функция выполняется, funImage заполняется одним изображением, но затем, когда я обновляю sh, он заполняется остальными моими изображениями, которые у меня есть в моей базе.

Взгляните на этот GIF моего работающего приложения и проблему с setState

1 Ответ

2 голосов
/ 06 мая 2020

Код не работает, потому что ваш forEach использует асинхронный c код. Это означает, что он завершит sh запуск после того, как вы установите свои изображения. Вот исправление с некоторыми пояснениями в комментариях -

// No need for images array outside
const [funImage, setFunImage] = useState([]);

...

firebase.firestore().collection('PostedFunActivities').where("location", "==" , place).get().then(async (querySnapshot) =>{
    // instead of foreach, using map to aggregate the created promises into one array
    // Promise.all takes an array of promises and resolves after all of them completed running
    // returns an array with the promise results
    const images = await Promise.all(querySnapshot.map(async(doc) =>{ 
        const ref = firebase.storage().ref('images/'+ doc.data().image)
        const result = await ref.getDownloadURL();
        return result;                                         
    }));
    setFunImage(images);
});
...