【问题标题】:My flatList is rendering before my api query finishes我的 flatList 在我的 api 查询完成之前呈现
【发布时间】:2022-01-06 21:13:23
【问题描述】:

我有一个名为 getRecados() 的异步函数,它可以访问 firebase 并获取我需要我的平面列表来呈现的所有数据:

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

我会在 homeScreen 渲染后立即调用它:

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

但是当我第一次打开 homeScreen 时,flatList 是空的,但是当我使用按钮再次执行 getRecados() 时,flatList 工作正常并显示来自 firebase 的数据,所以这让我得出结论 flatList 正在渲染在 getRecados() 可以第一次设置 fullData 的值之前,如何让它等待 getRecados 完成它所做的一切?

这是平面列表代码:

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

【问题讨论】:

  • 还有一些会导致问题的代码。比如你使用了 await 和 then,这会给你带来 promise 的问题。
  • @Ashish 我无法删除异步,因为如果没有等待,代码的 firebase 部分将无法工作。
  • 您必须使用async/awaitpromise/then。您可以在函数中同时使用这两种方式。
  • @Ashish 我试图将 getRecados 变成一个承诺,但正如我所说,我必须在从 firebase 查询时使用 await 关键字,所以我最终遇到了问题,因为我不能在承诺中使用 await
  • @PriyashreeBhadra 我已经解决了这个问题,刚刚发布了一个答案来解释我是如何做到的。

标签: javascript firebase react-native google-cloud-firestore async-await


【解决方案1】:

如果您调试代码,您可能会发现在将数据设置为 Recados 之前关闭加载。

而是在停止加载之前将数据设置为Recados

const getRecados = async () => {
    setRefreshing(true)
    try {
        const recadosRef = firebase.firestore().collection('recados');
        const records = await recadosRef.orderBy('timestamp', 'desc').get();
        if(records == undefined){
            Alert.alert("Erro ao consultar os recados!!!", err.message);
        }
        const recadosList = new Array();
        if (user_setor.length == 0) {
            records.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 {
            records.forEach(doc => {
                if (user_setor.includes(doc.data().remetente)) {
                    recadosList.push(doc)
                }
            })
        }
        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
        })));
        setRecados(fullData)
        setLoading(false)
    } catch (err) {
        Alert.alert("Erro ao consultar os recados!!!", err.message);
    }
    setRefreshing(false)
};

如果您使用async/await 代码应该是这样的

【讨论】:

  • 它没有帮助,我实际上认为加载没有做任何事情,它被声明为 useState(true) 一次,然后在 getRecados 中设置为 false,这实际上是它的唯一两次提到了,但不是我添加的,所以我害怕删除它。
  • @gralmeidan 检查更新代码
【解决方案2】:

只有一个条件是在您的 api 调用完成之前不显示FlatList。您已经在管理 loading 变量,因此请仅使用它

if(loading){
    // Show loader or actvityIndicator
}
else{
    // Your flat list code.
}

【讨论】:

  • 现在它会在显示空的平面列表之前做一些加载动画
  • 是的,这是正确的方法吗?直到我们有数据显示加载器
  • 问题是我们确实有数据,flatlist 是空的,因为由于某种原因它在存储数据的状态可以更新之前一直渲染
  • FlatList 无论如何都会在我们加载该组件后立即渲染,我们无法阻止它。我不明白你说“我们确实有数据”的意思。这是否意味着在调用 api 之前,您的状态变量中就有数据?
【解决方案3】:

我尝试了 Ashish 提出的使用 Promise/Then 而不是 Async/Await 的建议,它有点奏效了,使用 .get().then() 确实解决了数据未在 useEffect 上加载的问题,但它只加载了 4由于某种原因,我在 firebase 上拥有的 15 个文档中,所以对我有用的是使用 firebase 的 .onSnapshot() 函数 insted of .get(),这是生成的代码:

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

【讨论】:

    猜你喜欢
    • 2014-10-29
    • 2019-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-22
    相关资源
    最近更新 更多