4

I have this async function called getRecados() that reaches out to firebase and grab all the data I will need my flatlist to render:

const getRecados = () => {
    setRefreshing(true)
    try {
      const recadosRef = firebase.firestore().collection('recados');
      recadosRef.orderBy('timestamp', 'desc').get().then(snapshot => {
        const recadosList = new Array()
        // Does some filtering on the data it just grabbed from firebase
        if (user_setor.length == 0) {
          snapshot.forEach(doc => {
            if ((doc.data().curso_dest == user_curso
              || doc.data().curso_dest == '')
              && (doc.data().ano_dest == user_ano
                || doc.data().ano_dest == '')
              && (doc.data().turno_dest == user_turno
                || doc.data().turno_dest == ''))
              recadosList.push(doc)
          })
        } else {
          snapshot.forEach(doc => {
            if (user_setor.includes(doc.data().remetente)) {
              recadosList.push(doc)
            }
          })
        }
        // fullData is an useState
        setFullData(recadosList.map((doc) => ({
          id: doc.id,
          titulo: doc.data().titulo,
          timestamp: doc.data().timestamp,
          remetente: doc.data().remetente,
          curso_dest: doc.data().curso_dest,
          ano_dest: doc.data().ano_dest,
          turno_dest: doc.data().turno_dest,
          texto: doc.data().texto
        })))
        setLoading(false)
        setRecados(fullData)
      })

    } catch (err) {
      Alert.alert("Erro ao consultar os recados!!!", err.message);
    }
    setRefreshing(false)
  };

And I call it as soon as the homeScreen renders with:

useEffect(() => {
    getRecados()
  }, []);

But when I open the homeScreen for the first time the flatList is empty, but when I execute getRecados() again with a button the flatList works fine and displays the data from firebase, so that made me conclude that the flatList is rendering before getRecados() can set fullData's value for the first time, so how do I make it wait for getRecados to finish whatever its doing?

Here's the flatlist code:

<FlatList 
  data={recados}
  onRefresh={getRecados}
  refreshing={refreshing}
  showsVerticalScrollIndicator={false}
  renderItem={({ item }) => (
    <Card
      texto={item.texto}
      titulo={item.titulo}
      timestamp={item.timestamp}
      info1={item.remetente}
      info2={
        "ao " + item.ano_dest + "º " + item.curso_dest + " " + item.turno_dest
      }
    />
  )}
/>;
Ashish
  • 6,791
  • 3
  • 26
  • 48
gralmeidan
  • 51
  • 3
  • 1
    Still some of your code which will cause you problem. Such as you used await and then, which will give you problem of promise. – Ashish Nov 30 '21 at 05:07
  • @Ashish I can't remove the async because the firebase part of the code won't work without the await. – gralmeidan Nov 30 '21 at 05:17
  • 1
    Either you have to use `async/await` or `promise/then`. You can use both ways together in function. – Ashish Nov 30 '21 at 05:25
  • @Ashish I tried to turn getRecados into a promise but as I said I have to use the await keyword when querying from firebase so I ended up having problems because I can't use await inside a promise – gralmeidan Nov 30 '21 at 05:32
  • Please check my updated code. It will you to resolve your problem. – Ashish Nov 30 '21 at 05:37
  • @Ashish It "kind of" worked, now when the flatlist renders for the first time it only renders half of the data, and when I call refreshing it renders the rest of the data, I don't really know why as I'm literally executing the same code on both occasions – gralmeidan Nov 30 '21 at 05:53
  • When you work on frontend side you should be more relied on `Promise/Then` instead of `async/await`. Read the difference in [this](https://stackoverflow.com/questions/34401389/what-is-the-difference-between-javascript-promises-and-async-await) article – Ashish Nov 30 '21 at 05:56
  • @gralmeidan Were you able to resolve your issue? If not, I think the answer provided by Ashish is correct. Can you try that and confirm if that resolves your issue? – Priyashree Bhadra Dec 14 '21 at 13:05
  • 1
    @PriyashreeBhadra I already solved the issue and just posted an answer explaining how I did it. – gralmeidan Dec 15 '21 at 17:50

2 Answers2

1

I tried Ashish's suggestion of using Promise/Then instead of Async/Await and it kind of worked, using .get().then() did solve the problem of the data not loading on useEffect but it just loaded 4 of the 15 documents I had on firebase for some reason, so what worked for me was to use firebase's .onSnapshot() function insted of .get(), here's the resulting code:

const getRecados = async () => {
    setRefreshing(true);
    try {
      const recadosRecebidos = firebase
        .firestore()
        .collection("recados")
        .orderBy("timestamp", "desc")
        .onSnapshot(
          snapshot => {
               /*
                * Just filtering the data, has nothing to do with the problem;
                */
            }
              return result
            }, []);
            setFullData(recadosList);
            setRecados(recadosList);
          },
          () => {
            setError(true);
          }
        );
      setLoading(false);
    } catch (err) {
      Alert.alert("Erro ao consultar os recados!!!", err.message);
    }
    setRefreshing(false);
  };
gralmeidan
  • 51
  • 3
0

Simply have a condition for not to show FlatList until your api call is done. You are already managing loading variable so utilise that only like

if(loading){
    // Show loader or actvityIndicator
}
else{
    // Your flat list code.
}
Ravi
  • 34,851
  • 21
  • 122
  • 183
  • Now it does a little loading animation before displaying the empty flatlist – gralmeidan Nov 30 '21 at 05:29
  • yeah, that is what a proper way right? until we have data we are showing loader – Ravi Nov 30 '21 at 05:38
  • The problem is that we do have data, the flatlist is empty because for some reason it keeps rendering before the state that stores the data can be updated – gralmeidan Nov 30 '21 at 05:41
  • FlatList is anyhow going to render as soon as we load that component, we cannot stop that. I am not getting your point that says "we do have data". Does that mean you are having data inside your state variable even before you are calling an api? – Ravi Nov 30 '21 at 05:48