简体   繁体   English

如何在 React-Native 中成功注销并导航回主应用程序屏幕?

[英]How to successfully logout and navigate back to the main App screen in React-Native?

I need help figuring out the right way to logout and return to the Welcome screen.我需要帮助找出注销并返回欢迎屏幕的正确方法。

Currently, the RootStack queries the redux store for a token, and uses that to determine which group of screens will be available to the user.目前,RootStack 在 redux 存储中查询令牌,并使用它来确定用户可以使用哪组屏幕。

If a token exists we go into a TabNavigator called OrgTabs.如果存在令牌,我们将进入名为 OrgTabs 的 TabNavigator。 And that seems to be taking removing the parent navigator.这似乎正在移除父导航器。 And when I try to logout, the screen I want to navigate to doesn't exist within the navigation object.当我尝试注销时,导航对象中不存在我想要导航到的屏幕。

Please help!请帮忙! I'd really appreciate我真的很感激

Rootstack.js根堆栈.js

import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

//screens
import Welcome from '../screens/Welcome';
import SignIn from '../screens/SignIn';

import UserSignIn from '../screens/UserSignIn.js';

import StaffSignIn from '../screens/StaffSignIn';
import StaffSignUp from '../screens/StaffSignUp';

import OrgSignIn from '../screens/OrgSignIn';
import OrgSignUp from '../screens/OrgSignUp';
import OrgHomeScreen from '../screens/org/OrgHomeScreen';

import OrgTabs from '../components/molecules/OrgTabs';
import TestScreen from '../screens/org/TestScreen';

// selecetors and hooks
import { useSelector } from 'react-redux';
import { selectToken, selectRefreshToken } from '../features/user/userSlice';

const Stack = createStackNavigator();
const RootStack = () => {
    const token = useSelector(selectToken)
    const refreshToken = useSelector(selectRefreshToken)
    return (
        <NavigationContainer>
            <Stack.Navigator
                screenOptions={{
                    headerShown: true,
                    headerTitle:'',
                    headerTransparent: true
                }}
            >
                { token ?
                    (<Stack.Group>
                        <Stack.Screen name="OrgTabs" component={OrgTabs} />
                        <Stack.Screen name="Welcome" component={Welcome} />
                        <Stack.Screen name="TestScreen" component={TestScreen} />

                        <Stack.Screen name="SignIn" component={SignIn} />
                        <Stack.Screen name="UserSignIn" component={UserSignIn} />
                        <Stack.Screen name="StaffSignIn" component={StaffSignIn} />
                        <Stack.Screen name="StaffSignUp" component={StaffSignUp} />
                        <Stack.Screen name="OrgSignIn" component={OrgSignIn} />
                        <Stack.Screen name="OrgSignUp" component={OrgSignUp} />

                    </Stack.Group>
                    )

                    :
                    
                    // auth screens
                    (<Stack.Group>
                        <Stack.Screen name="Welcome" component={Welcome} />
                        <Stack.Screen name="SignIn" component={SignIn} />
                        <Stack.Screen name="UserSignIn" component={UserSignIn} />
                        <Stack.Screen name="StaffSignIn" component={StaffSignIn} />
                        <Stack.Screen name="StaffSignUp" component={StaffSignUp} />
                        <Stack.Screen name="OrgSignIn" component={OrgSignIn} />
                        <Stack.Screen name="OrgSignUp" component={OrgSignUp} />
                        <Stack.Screen name="OrgTabs" component={OrgTabs} />
                    </Stack.Group>
                    )
                }
                
            </Stack.Navigator>
        </NavigationContainer>
      );
}

export default RootStack;

StaffSignIn.js员工登录.js

import React from "react";
import { Text, TextInput, ActivityIndicator } from "react-native";
import { StatusBar } from 'expo-status-bar';
import { Formik, Form } from "formik";
import { useDispatch, useSelector } from "react-redux";

import { 
        LightContainer, PadlessContainer, FlexHoriztal,
        Header1, Header2, Header3, TextLight,
        AppLogo, StlyedButton,
        Pad_h_medium, Pad_h_small, Pad_w_small} from "../styles/styles";
import { TextLink, MsgBox } from "../components/atoms/Atoms";
import { StyldTextInput } from "../components/molecules/Molecules";
import { StyledFormArea } from "../components/organisms/Organisms";
import KeyboardAvoidingWrapper from "../components/organisms/KeyboardAvoidingWrapper";

import * as SecureStore from "expo-secure-store";
import axios from "axios";
import { setToken } from "../features/user/userSlice";
import {getToken} from "../features/user/User";

const logo_img = require("../assets/logo_red.png");
const chalk = require('chalk');

const StaffSignIn = ({navigation}) => {
    [message, setMessage] = React.useState("");
    [messageStatus, setMessageStatus] = React.useState("failed");
    [hidePassword, setHidePassword] = React.useState(true);
    const dispatch = useDispatch();

    const handleSubmit = (values, setSubmitting) => {

        const url = "https://dandle.dustinc.dev/signin/staff";
        axios.post(url, values)
        .then( (response) => {
            const result = response.data;
            const {success, user, token, refreshToken} = response.data;
            if(success === true) {
                setMessageStatus("success");
                setMessage("sign in successful");
                storeToken(token, refreshToken);
                
                dispatch(setToken(token));
                navigation.navigate("OrgTabs");
            }
            else if (success === false) {
                setMessageStatus("failed");
                setMessage("sign in failed");
            }
            setSubmitting(false);
        })
        .catch(err => {
            setSubmitting(false);
            // setMessage("Oops! Network error. Try again soon");
            if (err.response.status === 401) {
                setMessage("Invalid username or password");
            }
            else {
                setMessage("Oops! Network error. Try again soon");
            }
        })
        .finally(() => {
            setSubmitting(false);
        });
    }
    
    // function that will store a token and refresh token in react-native-keychain
    async function storeToken (token, refreshToken) {
        SecureStore.setItemAsync("token", token)
        .then(() => {
            SecureStore.setItemAsync("refreshToken", refreshToken)
            .then(() => {
                dispatch(setToken(token));
                dispatch(setToken(refreshToken));
                console.log("\x1b[32m successfully stored token and refresh-token\n");
                console.log("\x1b[0m token: ", token,'\n');
                console.log("refreshToken: ", refreshToken, '\n');
            })
            .catch(err => {
                console.log(err);
            });
        })
        .catch(err => {
            console.log(err);
        });
    }
    
    return (
        <KeyboardAvoidingWrapper>
            <LightContainer>
                <StatusBar style="dark" />
                <PadlessContainer>
                <Pad_h_medium /><Pad_h_medium />
                    <Formik
                        initialValues={{
                            username: "",
                            password: "",
                        }}
                        onSubmit={(values, {setSubmitting}) => {
                            handleSubmit(values, setSubmitting);
                        }}
                    >
                        {
                            ({handleChange, handleBlur, handleSubmit, isSubmitting, values}) => (
                                <StyledFormArea justify='center'>
                                    <StyldTextInput
                                        label="Username"
                                        placeholder="johndoe"
                                        onChangeText={handleChange("username")}
                                        value={values.username}
                                    />
                                    <StyldTextInput
                                        label="Password"
                                        placeholder="* * * * * * *"
                                        secureTextEntry={hidePassword}
                                        value={values.password}
                                        onChangeText={handleChange('password')}
                                        isPassword={true}
                                        hidePassword={hidePassword}
                                        setHidePassword={setHidePassword}
                                    />
                                    <Pad_h_medium /><Pad_h_medium /><Pad_h_medium />
                                    <Pad_h_medium /><Pad_h_medium /><Pad_h_medium />
                                    <MsgBox type={messageStatus}>{message}</MsgBox>
                                    {!isSubmitting && <StlyedButton onPress={handleSubmit} width='100%'>
                                        <TextLight>Sign in</TextLight>
                                    </StlyedButton>}<Pad_h_small />
                                    {isSubmitting && <StlyedButton width='100%' disabled={true}>
                                        <ActivityIndicator size="small" color="#fff" />
                                    </StlyedButton>}<Pad_h_small />
                                    
                                    <FlexHoriztal justify='center'>
                                    <Header2>Don't have an account?</Header2>
                                    <TextLink onPress={()=> navigation.navigate('StaffSignUp')}>
                                        <Header2>Register</Header2>
                                    </TextLink>
                                    </FlexHoriztal>
                                </StyledFormArea>
                            )
                        }
                    </Formik>    
                </PadlessContainer>
            </LightContainer>
        </KeyboardAvoidingWrapper>
    );
}

export default StaffSignIn;

OrgTabs.js组织标签.js

import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import {Octicons} from '@expo/vector-icons';

//screens
import OrgSettings from '../../screens/org/OrgSettings';
import OrgHomeScreen from '../../screens/org/OrgHomeScreen';
import OrgAnalytics from '../../screens/org/OrgAnalytics';
import OrgChat from '../../screens/org/OrgChat';


const Tab = createBottomTabNavigator();

export default function OrgTabs() {
  return (
    <NavigationContainer 
      independent={true}
    >
      <Tab.Navigator
        screenOptions={{
          tabBarShowLabel: false,
          tabBarStyle: {
            position: 'absolute',
            backgroundColor: '#f38484', 
            borderTopRightRadius: 2,
            borderTopLeftRadius: 2,
          },
          headerTransparent : true,
          headerShown: false,
          tabBarActiveBackgroundColor: '#d64547',
        }}
      >
        <Tab.Screen 
          name="Settings" 
          component={OrgSettings}
          options={{
            tabBarIcon: () => {
              return(
                <Octicons name='gear' size={25} color='white'/>
              )
            }
          }}
        />
        <Tab.Screen 
          name="Home" 
          component={OrgHomeScreen}
          options={{
            tabBarIcon: () => {
              return(
                <Octicons name='home' size={25} color='white'/>
              )
            }
          }} 
        />
        <Tab.Screen 
          name="Chat" 
          component={OrgChat} 
          options={{
            tabBarIcon: ({size,focused,color}) => {
              return(
                <Octicons name='comment-discussion' size={25} color='white'/>
              )
            }
          }}
        />
        <Tab.Screen 
          name="Analytics" 
          component={OrgAnalytics} 
          options={{
            tabBarIcon: ({size,focused,color}) => {
              return(
                <Octicons name='graph' size={25} color='white'/>
              )
            }
          }}
        />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

So the solution I came up with, was to display the message "Logged out" and then set the token in redux to Null.所以我想出的解决方案是显示消息“已注销”,然后将 redux 中的令牌设置为 Null。 And finally, reload the app using the Updates package, which is part of Expo.最后,使用 Expo 的一部分的 Updates 包重新加载应用程序。

So when you logout, the app is reloaded and the check for a token is repeated.因此,当您注销时,应用程序会重新加载并重复检查令牌。

Try this,I Hope it will work.试试这个,我希望它会起作用。

const logout=()=>{
    console.log("logout");
    AsyncStorage.getAllKeys()
        .then(keys => AsyncStorage.multiRemove(keys)).then(() => navigation.reset({ index: 0, routes: [{ name: "Login" }], }));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM