React Native:异步获取后不显示数据

React Native: data not displaying after async fetch

我正在使用 React Native 和 Expo 管理的工作流程开发移动应用程序。该应用程序应该用作一本歌曲集,其中包含歌曲和赞美诗的歌词。所有歌词都存储在 Firebase 的 Firestore 数据库中,客户可以在应用程序中加载它们。我开始实现离线功能,其中所有歌词都使用社区的 AsyncStorage.

存储在用户的设备上

我想先获取存储在 AsyncStorage 中的数据,将它们设置为保存歌曲的状态变量,然后查看用户是否可以访问互联网。如果是,我想检查 Firestore 中的更新,如果有,我会将 Firestore 中的数据设置为保存歌曲的状态变量。如果用户无法访问互联网,来自 AsyncStorage 的数据将已设置为保存歌曲的状态变量。

我试图通过 useEffect 挂钩中的异步函数实现这一点,空数组 vars/dependecies。 我遇到的问题是,即使从 AsyncStorage 成功检索到歌曲,屏幕上也没有呈现任何歌曲。

(当我 console.log 从 AsyncStorage 检索数据的输出时,我可以看到所有歌曲,当我控制日志歌曲或 allSongs 状态变量时,我变得不确定)

这是我的简化代码:

import React, { useEffect, useState } from 'react';
import {
  StyleSheet,
  FlatList,
  SafeAreaView,
  LogBox,
  View,
  Text,
} from 'react-native';
import { StatusBar } from 'expo-status-bar';
import { filter, _ } from 'lodash';
import { doc, getDoc } from 'firebase/firestore';
import NetInfo from '@react-native-community/netinfo';

import { db } from '../../../firebase-config';
import { ThemeContext } from '../../util/ThemeManager';
import {
  getStoredData,
  getStoredObjectData,
  storeData,
  storeObjectData,
} from '../../util/LocalStorage';

const SongsList = ({ route, navigation }) => {

  // const allSongs = props.route.params.data;
  const { theme } = React.useContext(ThemeContext);
  const [loading, setLoading] = useState(false);
  const [allSongs, setAllSongs] = useState();
  const [songs, setSongs] = useState(allSongs);
  const hymnsRef = doc(db, 'index/hymns');

  useEffect(() => {
    const setup = async () => {
      setLoading(true);
      const locData = await getStoredObjectData('hymnsData');
      console.log(locData);
      setAllSongs(locData);
      setSongs(locData);
      const netInfo = await NetInfo.fetch();
      if (netInfo.isInternetReachable) {
        const data = await getDoc(hymnsRef);
        const lastChangeDb = data.get('lastChange').valueOf();
        const hymnsData = data.get('all');
        const lastChangeLocal = await getStoredData('lastChange');
        if (lastChangeLocal) {
          if (lastChangeLocal !== lastChangeDb) {
            await storeData('lastChange', lastChangeDb);
            await storeObjectData('hymnsData', hymnsData);
            setAllSongs(hymnsData);
            setSongs(hymnsData);
          }
        }
      }
      sortHymns();
      setLoading(false);
    };
    setup();
  }, []);

  return (
    <SafeAreaView style={[styles.container, styles[`container${theme}`]]}>
      {!loading ? (
        <FlatList
          data={songs}
          keyExtractor={(item) => item?.number}
          renderItem={({ item }) => {
            return <ListItem item={item} onPress={() => goToSong(item)} />;
          }}
          ItemSeparatorComponent={Separator}
          ListHeaderComponent={
            route.params.filters ? (
              <SearchFilterBar
                filters={filters}
                handleFilter={handleFilter}
                query={query}
                handleSearch={handleSearch}
                seasonQuery={seasonQuery}
                setSeasonQuery={setSeasonQuery}
              />
            ) : (
              <SearchBar handleSearch={handleSearch} query={query} />
            )
          }
        />
      ) : (
        <View>
          <Text>loading</Text>
        </View>
      )}
      <StatusBar style={theme === 'dark' ? 'light' : 'dark'} />
    </SafeAreaView>
  );
};

export default SongsList;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

函数getStoredData、getStoredObjectData、storeData和storeObjectData只是AsyncStorage的getItem和setItem方法。

这是我的完整代码 - GitHub

我做错了什么?我浏览了很多教程和文章,它应该可以工作...但我猜不是?

你能检查一下 hymnsData 是否未定义吗?在 const hymnsData = data.get('all'); 行之后。

如果是这样,那就可以解释问题 - 您正确设置了 locData,但随后立即覆盖了它。如果是这样,我会将 hymnsData 添加到 if 条件 if (hymnsData && lastChangeLocal) { ... }

如果您在 return ( 之前记录歌曲和所有歌曲,您是否曾短暂地看到它们被填充?

我要调试的另一件事是注释掉

setAllSongs(hymnsData);
setSongs(hymnsData);

行并查看它是否按预期仅使用 locData

问题出在 sortHymns() 方法上。我将它从它自己的方法移到了 useEffect 并且它现在可以工作了。