我的 flatList 在我的 api 查询完成之前呈现

Posted

技术标签:

【中文标题】我的 flatList 在我的 api 查询完成之前呈现【英文标题】:My flatList is rendering before my api query finishes 【发布时间】: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 我已经解决了这个问题,刚刚发布了一个答案来解释我是如何做到的。 【参考方案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);
  ;

【讨论】:

以上是关于我的 flatList 在我的 api 查询完成之前呈现的主要内容,如果未能解决你的问题,请参考以下文章

我编写了用于在反应中列出书籍的代码,但 FlatList 在我的代码中不起作用,我该如何解决?

在 FlatList React Native 中仅显示 10 条记录

FlatList 动态高度调整

React Native 与 Expo 应用程序不呈现 FlatList

仅在 FlatList 顶部时向下滑动模态

Flatlist 项目在模态框内不可点击