React native 使用AsyncStorage登录后,React本机React导航屏幕不会重定向

React native 使用AsyncStorage登录后,React本机React导航屏幕不会重定向,react-native,authentication,react-navigation,asyncstorage,React Native,Authentication,React Navigation,Asyncstorage,因此,我构建了一个带有React-Native、React-Navigation和AsyncStorage的登录系统。如果用户单击某个按钮,他将登录,并且异步存储密钥“@loginuser”的值将刷新。现在我想 屏幕会自动刷新,但我必须关闭应用程序并重新启动它-这不是最优的 (我也看到了这篇文章,但它很旧) App.js 从“React”导入React; 从“react native”导入{Text,View,StyleSheet,Button,TouchableOpacity,TextInpu

因此,我构建了一个带有React-Native、React-Navigation和AsyncStorage的登录系统。如果用户单击某个按钮,他将登录,并且异步存储密钥“@loginuser”的值将刷新。现在我想 屏幕会自动刷新,但我必须关闭应用程序并重新启动它-这不是最优的

(我也看到了这篇文章,但它很旧)

App.js

从“React”导入React;
从“react native”导入{Text,View,StyleSheet,Button,TouchableOpacity,TextInput};
从“./components/Navigation/Navigation”导入DefaultStackNavigation;
常量应用=()=>{
返回(
)
}
导出默认应用程序;
Navigation.js

import React,{useffect,useState}来自“React”;
//自然反应
从“react native”导入{Text,View,StyleSheet};
//屏风
从“../HomeScreen/HomeScreen”导入主屏幕
从“./AddScreen/AddScreen”导入AddScreen;
从“./NotificationScreen/NotificationScreen”导入NotificationScreen;
从“./MenuScreen/MenuScreen”导入菜单屏幕;
从“./SearchScreen/SearchScreen”导入搜索屏幕;
从“./PostJobScreen/PostJobScreen”导入PostJobScreen;
从“./JobOfferScreen/JobOfferScreen”导入JobOfferScreen;
从“./ProfileScreen/ProfileScreen”导入ProfileScreen;
从“./NoneLoggedinScreen/NoneLoggedinScreen”导入NoneLoggedinScreen
从“./NoneLoggedinScreen/SignupModal”导入SignupModal
//反应导航
从“@react navigation/stack”导入{createStackNavigator};
从'@react-navigation/native'导入{NavigationContainer};
从“@react navigation/bottom tabs”导入{createBottomTabNavigator};
//第三方
从“@react native async storage/async storage”导入异步存储;
const Tab=createBottomTabNavigator();
//选项卡栏
常量HomeTabs=()=>{
返回(
}}/>
}}/>
);
}
const Stack=createStackNavigator();
const STORAGE_KEY='@loginStatus'
常量DefaultStackNavigation=()=>{
const[loginStatus,setLoginStatus]=useState()
const readData=async()=>{
试一试{
const isLoggedIn=JSON.parse(等待AsyncStorage.getItem(存储密钥))
console.log(isLoggedIn)
如果(isLoggedIn!==null){
setLoginStatus(isLoggedIn)
}
}捕获(e){
警报('未能从存储器中获取数据')
}
}
readData()
返回登录状态(
) : (
);
};
导出默认堆栈导航;
NoneLoggedinScreen.js

import React, { useState, useEffect } from 'react';
import { Text, View, Button} from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';

const STORAGE_KEY = '@loginStatus'

const SignupModal = () => {

  const [loginStatus, setLoginStatus] = useState(false)
  const saveData = async (parmLoginStatus) => {
    try {
      await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(parmLoginStatus))
      alert('Data successfully saved -> Logged In')
      console.log(loginStatus)
    } catch (e) {
      alert('Failed to save the data to the storage')
    }
  }

  const onSubmitLogin = () => {
    setLoginStatus(true)
    saveData(true)
  }


  return(
    <View>
      <Text>Login Page. Press the button to log in and stay logged in</Text>
      <Button title="Log in" onPress={() => onSubmitLogin()}/>
    </View>
  );
};

const styles = StyleSheet.create({
  App: {
    flex: 1,
    backgroundColor: "white"
  },
});

export default SignupModal;
import React,{useState,useffect}来自“React”;
从“react native”导入{文本、视图、按钮};
从“@react native async storage/async storage”导入异步存储;
const STORAGE_KEY='@loginStatus'
const SignupModal=()=>{
const[loginStatus,setLoginStatus]=useState(false)
const saveData=async(parmLoginStatus)=>{
试一试{
等待AsyncStorage.setItem(存储密钥,JSON.stringify(parmLoginStatus))
警报('数据已成功保存->已登录')
console.log(loginStatus)
}捕获(e){
警报('未能将数据保存到存储器')
}
}
const onSubmitLogin=()=>{
setLoginStatus(真)
保存数据(真)
}
返回(
登录页面。按按钮登录并保持登录状态
onSubmitLogin()}/>
);
};
const styles=StyleSheet.create({
应用程序:{
弹性:1,
背景颜色:“白色”
},
});
导出默认注册模式;
现在,我期待着页面重新加载,我可以使用该应用程序。不幸的是,事实并非如此。数据已保存,登录状态设置为
true
,但我必须重新启动应用程序才能使用它。背信弃义的事情是,如果我将异步存储登录逻辑从
NoneLoggedinScreen.js
文件写入App.js文件,应用程序工作正常->但是,这对我来说不是一个替代方案,因为我认为,应用程序的总体结构是相对合理的。 此外,当用户尝试手动(通过按钮)重定向navigation.navigate(“HomeTabs”)时,登录后无法工作,并且我收到一个错误,即Home不存在,这也是不可理解的,因为导航实际上已设置为现在登录。有人有过这个问题吗

顺便说一下,这是我的依赖项 “依赖项”:{
@react本机异步存储/异步存储“^1.15.1”,
@react本地社区/屏蔽视图“^0.1.10”,
“@react导航/底部选项卡”:“^5.11.7”,
@react导航/native:“^5.9.2”,
@react导航/堆栈“^5.14.2”,
“反应”:“16.13.1”,
“反应本机”:“0.63.4”,
“反应本机手势处理程序”:“^1.10.1”,
“反应本地复活”:“^1.13.2”,
“反应本机安全区域上下文”:“^3.1.9”,
“反应本机屏幕”:“^2.17.1”,

},

在您的身份验证策略中,存在一个隐藏的假设,即当您在
nonelogedInScreen
中使用AsyncStorage保存数据时,将立即使用
DefaultStackNavigation
中的
readData
功能读取数据。之所以不会发生这种情况,是因为只有在
DefaultStackNavigation
呈现/重新呈现时才会调用
readData
。当它的一个子项在本地存储中设置某些数据时,不会发生这种情况

有很多方法可以解决这个问题。将redux与redux persist或其他状态管理和持久性设置一起使用,或使用专门构建的基于上下文的解决方案(例如,请参阅有关的Kent C.Dodds文章)


你提到的第二个小问题:

登录后导航(“HomeTabs”)不起作用,我得到一个错误,Home不存在

确实有意义,其背后的原因是有条件地呈现两个不同的
导航容器。他们不知道彼此的路线,所以你不能在他们之间导航

修正
import React from "react";
import NoneLoggedinScreen from "../NoneLoggedinScreen/NoneLoggedinScreen";
import SignupModal from "../NoneLoggedinScreen/SignupModal";
import { createStackNavigator } from "@react-navigation/stack";

const Stack = createStackNavigator();

const AuthNavigator = () => {
  return (
    <Stack.Navigator screenOptions={{ headerShown: false }} independent={false}>
      <Stack.Screen name="NoneLoggedinScreen" component={NoneLoggedinScreen} />
      <Stack.Screen name="SignupModal" component={SignupModal} />
    </Stack.Navigator>
  );
};

export default AuthNavigator;
import React from "react";
import HomeScreen from "../HomeScreen/HomeScreen";
import AddScreen from "../AddScreen/AddScreen";
import NotificationScreen from "../NotificationScreen/NotificationScreen";
import MenuScreen from "../MenuScreen/MenuScreen";
import PostJobScreen from "../PostJobScreen/PostJobScreen";
import ProfileScreen from "../ProfileScreen/ProfileScreen";
import { createStackNavigator } from "@react-navigation/stack";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";

const Tab = createBottomTabNavigator();

//Tab bar
const HomeTabs = () => {
  return (
    <Tab.Navigator
      tabBarOptions={
        ({ style: { height: 50 } }, { showIcon: true }, { showLabel: false })
      }
    >
      <Tab.Screen name="Home" component={HomeScreen} />
      <Tab.Screen name="SearchScreen" component={SearchJobStack} />
      <Tab.Screen name="AddScreen" component={AddScreen} />
      <Tab.Screen name="NotificationScreen" component={NotificationScreen} />
      <Tab.Screen name="MenuScreen" component={MenuScreen} />
    </Tab.Navigator>
  );
};

const Stack = createStackNavigator();

const AppNavigator = () => {
  return (
    <Stack.Navigator screenOptions={{ headerShown: false }} independent={false}>
      <Stack.Screen name="HomeTabs" component={HomeTabs} />
      <Stack.Screen name="PostJobScreen" component={PostJobScreen} />
      <Stack.Screen name="ProfileScreen" component={ProfileScreen} />
    </Stack.Navigator>
  );
};

export default AppNavigator;
import React, { useState, useEffect } from 'react';
import { NavigationContainer } from '@react-navigation/native';

import AuthStorage from './auth/storage';
import AppNavigator from './navigation/AppNavigator';
import AuthNavigator from './navigation/AuthNavigator';

const App = () => {
  const [loginStatus, setLoginStatus] = useState(false);

  // I am using useEffect hook but I would prefer using `AppLoading` to restore token if it exists
  useEffect(() => {
    readData();
  }, []);

  const readData = async () => {
    try {
      const isLoggedIn = JSON.parse(await AuthStorage.getItem());
      console.log(isLoggedIn);
      if (isLoggedIn !== null) {
        setLoginStatus(isLoggedIn);
      }
    } catch (e) {
      alert('Failed to fetch the data from storage');
    }
  };

  return (
    <NavigationContainer>
      {loginStatus ? <AppNavigator /> : <AuthNavigator />}
    </NavigationContainer>
  );
};

export default App;
import AsyncStorage from '@react-native-async-storage/async-storage';

const AuthToken = '@loginStatus';

const storeItem = async (value) => {
  try {
    await AsyncStorage.setItem(AuthToken, JSON.stringify(value));
    return true;
  } catch (e) {
    return false;
  }
};

const getItem = async () => {
  try {
    const jsonValue = await AsyncStorage.getItem(AuthToken);
    return jsonValue != null ? JSON.parse(jsonValue) : null;
  } catch (e) {
    return null;
  }
};

export default { storeItem, getItem };