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 并且它现在可以工作了。
我正在使用 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 并且它现在可以工作了。