使用反应导航实现加载屏幕的最佳方法是什么(我想在显示导航之前将数据加载到上下文中
What is the best way to implement a loading screen with react navigation (I want to load data into context before navigation is displayed
我不知道我问的这个问题对不对,但就这样吧。我使用 Context API 来存储全局状态。当应用程序加载时,我会显示一个启动画面(我在本机执行此操作,而不是构建托管应用程序/Expo)。在后台,我想将一些数据加载到全局上下文对象中(在本例中为 UserProfileContext)。完成后,我将显示主导航。我认为代码会清楚地说明我要做什么。
问题是在显示导航路线之前我无法访问全局上下文,因为我使用上下文对象来包装导航组件。我怎样才能完成我想做的事情?
如果有更好的方法在选择我的路线之前加载一些数据,我愿意更改导航的结构and/or app.
这是我的导航代码:
const Stack = createStackNavigator()
const Drawer = createDrawerNavigator()
function CheckinStack() {
return (
<Stack.Navigator headerMode={'none'}>
<Stack.Screen
name={'Search Locations'}
component={SearchLocationsScreen}
/>
<Stack.Screen
name={'Check In Form'}
component={CheckInFormScreen}
/>
<Stack.Screen
name={'Checked In'}
component={CheckedInScreen}
/>
<Stack.Screen
name={'Business Details'}
component={BusinessDetailsScreen}
/>
</Stack.Navigator>
)
}
function MainDrawer() {
const {updateUserProfile} = useContext(UserProfileContext);
const [isLoading, setIsLoading] = useState(true)
const load = async () => {
try {
const profile = await retrieveUserProfile()
profile && updateUserProfile(profile)
setIsLoading(false)
} catch (e) {
}
}
if(isLoading){
return <LoadingScreen setIsLoading={setIsLoading}/>
}
return (
<Drawer.Navigator
drawerStyle={{
width: Dimensions.get('window').width > 600 ? '50%' : '70%',
maxWidth: 400,
}}
drawerContent={(props) => <CustomDrawerContent {...props} dataLoaded />}>
<Drawer.Screen name={'Search Locations'} component={CheckinStack} />
<Drawer.Screen name={'About'} component={AboutScreen} />
<Drawer.Screen name={'Favorites'} component={FavoritesScreen} />
<Drawer.Screen name={'Profile'} component={ProfileScreen} />
<Drawer.Screen name={'Report Issues'} component={ReportIssuesScreen} />
</Drawer.Navigator>
)
}
const NavContainer = () => {
return (
<NavigationContainer>
<UserLocationProvider>
<BusinessLocationsProvider>
<UserProfileProvider>
<CheckInProvider>
<FavoritesProvider>
<MainDrawer />
</FavoritesProvider>
</CheckInProvider>
</UserProfileProvider>
</BusinessLocationsProvider>
</UserLocationProvider>
</NavigationContainer>
)
}
在上下文中维护一个 isLoading
状态。在您的上下文中,根据 isLoading
状态有条件地渲染一些 Loading
组件或 {props.children}
。请求完成后初始化isLoading
为true,设置为false。但是,您必须在上下文中提出请求。
好吧,我不知道这是不是最好的方法,但这是我想出的方法。
这是我的顶级导航器功能:
// Main Navigation -------------------
const NavDrawer = ({route}) => {
const [isLoading, setIsLoading] = useState(true)
if (isLoading) {
return <LoadingScreen setIsLoading={setIsLoading} />
}
return (
<Drawer.Navigator
initialRouteName="Search Locations"
drawerStyle={styles.drawerStyle}
backBehavior="firstRoute"
drawerType="slide"
drawerContent={(props) => <DrawerContent {...props} />}>
<Drawer.Screen name="Search Locations" component={CheckIn} />
<Drawer.Screen name="About" component={About} />
<Drawer.Screen name='Favorites' component={Favorites} />
<Drawer.Screen name='Profile' component={Profile} />
<Drawer.Screen name='Report Issues' component={Issues} />
</Drawer.Navigator>
)
}
我实现了这样一个 LoadingScreen:
const LoadingScreen = ({setIsLoading}) => {
const { updateUserProfile } = useContext(UserProfileContext)
const { loadFavorites } = useContext(FavoriteLocationsContext)
const { checkInUser } = useContext(CheckInContext)
const loadAppData = async () => {
try {
const profile = await retrieveUserProfile()
if (profile) {
updateUserProfile(profile)
}
const favorites = await retrieveFavorites()
if (favorites) {
loadFavorites(favorites)
}
const checkinData = await retrieveCheckinData()
if (checkinData && checkinData.checkedIn) {
checkInUser(checkinData)
}
} catch (e) {
throw e
}
}
useEffect(() => {
loadAppData()
.then(() => {
setIsLoading(false)
})
.catch((e) => {
console.log('LoadingScreen: ', e.message)
setIsLoading(false)
})
}, [])
return null
}
export default LoadingScreen
我认为代码是不言自明的。我希望这对某人有所帮助,如果有人有更好的建议,我会更改已接受的答案。
我不知道我问的这个问题对不对,但就这样吧。我使用 Context API 来存储全局状态。当应用程序加载时,我会显示一个启动画面(我在本机执行此操作,而不是构建托管应用程序/Expo)。在后台,我想将一些数据加载到全局上下文对象中(在本例中为 UserProfileContext)。完成后,我将显示主导航。我认为代码会清楚地说明我要做什么。
问题是在显示导航路线之前我无法访问全局上下文,因为我使用上下文对象来包装导航组件。我怎样才能完成我想做的事情?
如果有更好的方法在选择我的路线之前加载一些数据,我愿意更改导航的结构and/or app.
这是我的导航代码:
const Stack = createStackNavigator()
const Drawer = createDrawerNavigator()
function CheckinStack() {
return (
<Stack.Navigator headerMode={'none'}>
<Stack.Screen
name={'Search Locations'}
component={SearchLocationsScreen}
/>
<Stack.Screen
name={'Check In Form'}
component={CheckInFormScreen}
/>
<Stack.Screen
name={'Checked In'}
component={CheckedInScreen}
/>
<Stack.Screen
name={'Business Details'}
component={BusinessDetailsScreen}
/>
</Stack.Navigator>
)
}
function MainDrawer() {
const {updateUserProfile} = useContext(UserProfileContext);
const [isLoading, setIsLoading] = useState(true)
const load = async () => {
try {
const profile = await retrieveUserProfile()
profile && updateUserProfile(profile)
setIsLoading(false)
} catch (e) {
}
}
if(isLoading){
return <LoadingScreen setIsLoading={setIsLoading}/>
}
return (
<Drawer.Navigator
drawerStyle={{
width: Dimensions.get('window').width > 600 ? '50%' : '70%',
maxWidth: 400,
}}
drawerContent={(props) => <CustomDrawerContent {...props} dataLoaded />}>
<Drawer.Screen name={'Search Locations'} component={CheckinStack} />
<Drawer.Screen name={'About'} component={AboutScreen} />
<Drawer.Screen name={'Favorites'} component={FavoritesScreen} />
<Drawer.Screen name={'Profile'} component={ProfileScreen} />
<Drawer.Screen name={'Report Issues'} component={ReportIssuesScreen} />
</Drawer.Navigator>
)
}
const NavContainer = () => {
return (
<NavigationContainer>
<UserLocationProvider>
<BusinessLocationsProvider>
<UserProfileProvider>
<CheckInProvider>
<FavoritesProvider>
<MainDrawer />
</FavoritesProvider>
</CheckInProvider>
</UserProfileProvider>
</BusinessLocationsProvider>
</UserLocationProvider>
</NavigationContainer>
)
}
在上下文中维护一个 isLoading
状态。在您的上下文中,根据 isLoading
状态有条件地渲染一些 Loading
组件或 {props.children}
。请求完成后初始化isLoading
为true,设置为false。但是,您必须在上下文中提出请求。
好吧,我不知道这是不是最好的方法,但这是我想出的方法。
这是我的顶级导航器功能:
// Main Navigation -------------------
const NavDrawer = ({route}) => {
const [isLoading, setIsLoading] = useState(true)
if (isLoading) {
return <LoadingScreen setIsLoading={setIsLoading} />
}
return (
<Drawer.Navigator
initialRouteName="Search Locations"
drawerStyle={styles.drawerStyle}
backBehavior="firstRoute"
drawerType="slide"
drawerContent={(props) => <DrawerContent {...props} />}>
<Drawer.Screen name="Search Locations" component={CheckIn} />
<Drawer.Screen name="About" component={About} />
<Drawer.Screen name='Favorites' component={Favorites} />
<Drawer.Screen name='Profile' component={Profile} />
<Drawer.Screen name='Report Issues' component={Issues} />
</Drawer.Navigator>
)
}
我实现了这样一个 LoadingScreen:
const LoadingScreen = ({setIsLoading}) => {
const { updateUserProfile } = useContext(UserProfileContext)
const { loadFavorites } = useContext(FavoriteLocationsContext)
const { checkInUser } = useContext(CheckInContext)
const loadAppData = async () => {
try {
const profile = await retrieveUserProfile()
if (profile) {
updateUserProfile(profile)
}
const favorites = await retrieveFavorites()
if (favorites) {
loadFavorites(favorites)
}
const checkinData = await retrieveCheckinData()
if (checkinData && checkinData.checkedIn) {
checkInUser(checkinData)
}
} catch (e) {
throw e
}
}
useEffect(() => {
loadAppData()
.then(() => {
setIsLoading(false)
})
.catch((e) => {
console.log('LoadingScreen: ', e.message)
setIsLoading(false)
})
}, [])
return null
}
export default LoadingScreen
我认为代码是不言自明的。我希望这对某人有所帮助,如果有人有更好的建议,我会更改已接受的答案。