我的 React Native 导航与 React-navigation 有一个导航错误

问题描述 投票:0回答:1

我正在开发一个小型 React Native 应用程序,并且正在使用 React-navigation/native。我的页面上有一个小错误,我一生都无法弄清楚。但首先,这是我的导航堆栈页面:

  import { NavigationContainer } from "@react-navigation/native";
  import { createNativeStackNavigator } from "@react-navigation/native-stack";
  import LoadPage from "./screens/LoadPage";
  import WelcomePage from "./screens/WelcomePage";
  import Signup from "./screens/Signup";
  import Login from "./screens/Login";
  import ResetPassword from "./screens/ResetPassword";
  import Dashboard from "./screens/Dashboard";
  import Onboarding1 from "./screens/Onboarding1";
  import Onboarding2 from "./screens/Onboarding2";
  import Onboarding3 from "./screens/Onboarding3";
  import { GeneralAppProvider } from "./context/GeneralAppContext";

  const Stack = createNativeStackNavigator();

  export default function App() {
    return (
      <GeneralAppProvider>
        <NavigationContainer>
          <Stack.Navigator>
            <Stack.Screen
              name="Home"
              component={LoadPage}
              options={{ headerShown: false, gestureEnabled: false }}
            />
            <Stack.Screen
              name="Welcome"
              component={WelcomePage}
              options={{ headerShown: false, gestureEnabled: false }}
            />
            <Stack.Screen
              name="Signup"
              component={Signup}
              options={{ headerShown: false, gestureEnabled: false }}
            />
            <Stack.Screen
              name="Login"
              component={Login}
              options={{ headerShown: false, gestureEnabled: false }}
            />
            <Stack.Screen
              name="ResetPassword"
              component={ResetPassword}
              options={{ headerShown: false, gestureEnabled: false }}
            />
            <Stack.Screen
              name="Onboarding1"
              component={Onboarding1}
              options={{ headerShown: false, gestureEnabled: false }}
            />
            <Stack.Screen
              name="Onboarding2"
              component={Onboarding2}
              options={{ headerShown: false, gestureEnabled: false }}
            />
            <Stack.Screen
              name="Onboarding3"
              component={Onboarding3}
              options={{ headerShown: false, gestureEnabled: false }}
            />
            <Stack.Screen
              name="Dashboard"
              component={Dashboard}
              options={{ headerShown: false, gestureEnabled: false }}
            />
          </Stack.Navigator>
        </NavigationContainer>
      </GeneralAppProvider>
    );
  }

LoadPage 是我进入应用程序的入口页面,如下所示。它旨在导航到两个屏幕中的任何一个:未登录的用户的欢迎页面和已登录的用户的仪表板页面,具体取决于我是否有用户会话(我在 supabase 的帮助下管理它):

import { useFonts, Poppins_600SemiBold } from "@expo-google-fonts/poppins";
import { useEffect } from "react";
import { Text, View } from "react-native";
import { useGeneralAppContext } from "../utils/useGeneralAppContext";
import AsyncStorage from "@react-native-async-storage/async-storage";

export default function LoadPage({ navigation }) {

    const { session, generalDispatch } = useGeneralAppContext()

    const expirationTime = session?.expires_at;
    const currentTimestamp = Math.floor(Date.now() / 1000); // Current timestamp in seconds

    const hasExpired = currentTimestamp >= expirationTime;
    console.log(currentTimestamp, expirationTime)

    useEffect(() => {
        async function removeUserInfo() {
            try {
                await AsyncStorage.removeItem('user');
            } catch (error) {
                console.error(error)
            }
        }

        function goToPage() {
            if (session && !hasExpired) {
                navigation.replace('Dashboard')
            } else {
                removeUserInfo()
                generalDispatch({
                    type: 'setUser',
                    payload: {
                        userPayload: null,
                    },
                });
                navigation.replace('Welcome')
            }
        }
        setTimeout(() => {
            goToPage()
            generalDispatch({
                type: 'setLoadPageShown',
                payload: {
                    loadPageShownPayload: true,
                },
            });
        }, 3000)

    }, [])

    let [fontsLoaded, fontsError] = useFonts({
        Poppins_600SemiBold
    })

    if (!fontsLoaded && !fontsError) {
        return null;
    }

    return (
        <View className="flex-1 items-center justify-center bg-white">
            <Text style={{ fontFamily: 'Poppins_600SemiBold' }} className='text-[#1e1e1e] text-[32px]'>Card Vault</Text>
        </View>
    )
}

现在,当我尝试成功登录或注册用户时,如下所示,它会重定向回 LoadPage 而不是仪表板或入职页面(基于是否是登录或注册会话)。 登录页面是这样的

import { useFonts, Poppins_600SemiBold, Poppins_400Regular, Poppins_500Medium } from "@expo-google-fonts/poppins";
import { useState } from "react";
import { ActivityIndicator, Image, SafeAreaView, ScrollView, Text, TextInput, TouchableOpacity, View } from "react-native";
import Icon from 'react-native-vector-icons/AntDesign';
import { Keyboard, TouchableWithoutFeedback } from 'react-native'
import FaIcon from 'react-native-vector-icons/FontAwesome5'
import { supabase } from "../utils/supabase";
import { useGeneralAppContext } from "../utils/useGeneralAppContext";
import AsyncStorage from "@react-native-async-storage/async-storage";

export default function Login({ navigation }) {

    let [fontsLoaded, fontsError] = useFonts({
        Poppins_600SemiBold,
        Poppins_400Regular,
        Poppins_500Medium
    })

    const [loading, setLoading] = useState(false)
    const [showPassword, setShowPassword] = useState(false)
    const [error, setError] = useState({
        type: '',
        message: ''
    })
    const [userInfo, setUserInfo] = useState({
        email: '',
        password: '',
        passwordConfirm: ''
    })


    const { email, password } = userInfo
    const { generalDispatch } = useGeneralAppContext()

    async function handleLogin() {
        // Regular expression for validating an Email
        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

        if (email === '') {
            setError({
                type: 'Error',
                message: 'Email cannot be empty'
            })
        } else if (password === '') {
            setError({
                type: 'Error',
                message: 'Password cannot be empty'
            })
        } else if (!emailRegex.test(email)) {
            setError({
                type: 'Error',
                message: 'Enter a valid email'
            })
        } else {
            try {
                setLoading(true)
                let { data, error } = await supabase.auth.signInWithPassword({
                    email: email,
                    password: password
                })

                console.log(data, error)
                if (error) {
                    setError({
                        type: 'Error',
                        message: error.message
                    })
                } else {
                    generalDispatch({
                        type: 'setUserSession',
                        payload: {
                            sessionPayload: data.session
                        }
                    })
                    generalDispatch({
                        type: 'setUser',
                        payload: {
                            userPayload: data.user
                        }
                    })

                    await AsyncStorage.setItem('user', JSON.stringify(data.user));
                    navigation.replace('Dashboard')
                }
            } catch (error) {
                console.error(error)
            } finally {
                setLoading(false)
            }
        }

        setTimeout(() => {
            setError({ type: '', message: '' })
        }, 3000)
    }

    if (!fontsLoaded && !fontsError) {
        return null;
    }

    return (
        <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
            <SafeAreaView>
                <ScrollView className='p-6'>
                    <TouchableOpacity onPress={() => navigation.goBack()}>
                        <Icon
                            name="arrowleft"
                            size={24}
                        />
                    </TouchableOpacity>
                    <Text style={{ fontFamily: 'Poppins_600SemiBold' }} className='text-[#1E1E1E] mt-8 text-[24px]'>Reset Password</Text>

                    <View className='mt-8'>
                        <View className=''>
                            <Text style={{ fontFamily: 'Poppins_400Regular' }} className='text-sm text-[#1E1E1E]'>Email</Text>
                            <TextInput
                                placeholder="Enter your email address"
                                value={email}
                                style={{ fontFamily: 'Poppins_400Regular' }}
                                onChangeText={text => setUserInfo((prevInfo) => ({ ...prevInfo, email: text }))}
                                keyboardType="email-address"
                                className='bg-transparent rounded-lg border-[1px] mt-2 border-[#E0E0E0] py-3 px-4 focus:border-[1px] focus:border-[#000000]'
                            />
                        </View>
                        <View className='mt-8 '>
                            <Text style={{ fontFamily: 'Poppins_400Regular' }} className='text-sm text-[#1E1E1E]'>Password</Text>
                            <View className='flex flex-row items-center relative'>
                                <TextInput
                                    placeholder="Enter your password"
                                    value={password}
                                    onChangeText={text => setUserInfo((prevInfo) => ({ ...prevInfo, password: text }))}
                                    secureTextEntry={showPassword ? false : true}
                                    style={{ fontFamily: 'Poppins_400Regular' }}
                                    className='flex-1 bg-blue-300w-full rounded-lg border-[1px] mt-2 border-[#E0E0E0] py-3 px-4 focus:border-[#000000]'
                                />
                                <TouchableOpacity onPress={() => setShowPassword(!showPassword)} className='absolute right-4 bottom-3'>
                                    <FaIcon
                                        name={showPassword ? 'eye' : 'eye-slash'}
                                        size={20}
                                    />
                                </TouchableOpacity>
                            </View>
                        </View>
                        <TouchableOpacity onPress={() => navigation.navigate('ResetPassword')}>
                            <Text style={{ fontFamily: 'Poppins_400Regular' }} className='text-[#4169E1] mt-2'>Forgot Password?</Text>
                        </TouchableOpacity>

                        <View className={`w-full p-3 rounded-md mt-8 border-[1px] border-[#b2afaf] bg-red-400 ${error.message === '' ? 'hidden' : ''}`}>
                            <Text style={{ fontFamily: 'Poppins_500Medium' }} className='text-white'>{error.message}</Text>
                        </View>

                    </View>
                    <View className='mt-20'>
                        <TouchableOpacity className='mt-12 w-full' onPress={handleLogin} disabled={loading}>
                            <View className='bg-[#4169E1] py-[18px] flex items-center rounded-xl'>
                                {loading ?
                                    <ActivityIndicator size="small" color="#ffffff" /> :
                                    <Text style={{ fontFamily: 'Poppins_400Regular' }} className='text-[#ffffff] text-sm'>Login</Text>
                                }
                            </View>
                        </TouchableOpacity>
                        {/* <View className='flex flex-row justify-between items-center py-8 gap-4'>
                            <View className='flex-1 border-b-[1px] border-[#a7a9ab]'></View>
                            <Text className='text-[#a7a9ab]'>OR</Text>
                            <View className='flex-1 border-b-[1px] border-[#a7a9ab]'></View>
                        </View>
                        <TouchableOpacity className='w-full'>
                            <View className='border-[1px] border-[#DADADA] py-[18px] flex flex-row justify-center items-center  rounded-xl'>
                                <Image
                                    source={require('../assets/flat-color-icons-google.png')}
                                />
                                <Text style={{ fontFamily: 'Poppins_500Medium' }} className='text-[#1C1C1C] ml-2 text-sm'>Continue with Google</Text>
                            </View>
                        </TouchableOpacity> */}
                    </View>
                    <View className='flex flex-row items-center gap-1 justify-center mt-10'>
                        <Text style={{ fontFamily: 'Poppins_400Regular' }} className='text-[#1E1E1E]'>Don't have an account?</Text>
                        <TouchableOpacity onPress={() => navigation.navigate('Signup')}>
                            <Text style={{ fontFamily: 'Poppins_400Regular' }} className='text-[#4169E1]'>Sign Up</Text>
                        </TouchableOpacity>
                    </View>
                </ScrollView>
            </SafeAreaView>
        </TouchableWithoutFeedback>
    )
}

如果用户已登录并且我尝试从仪表板页面注销,也会发生同样的情况。它会在再次重定向之前重定向到 LoadPage。

用户应该被直接定向到导航上指定的页面。我尝试过在导航上使用替换、推送、弹出导航方法,但一切仍然以相同的方式发生。

react-native react-navigation react-native-navigation supabase nativewind
1个回答
0
投票

我想可能是因为这个功能:

function goToPage() {
  if (session && !hasExpired) {
    navigation.replace('Dashboard')
  } else {
    removeUserInfo()
    generalDispatch({ type: 'setUser', payload: { userPayload: null } });
    navigation.replace('Welcome')
  }
}

也需要异步,然后等待

removeUserInfo()

类似这样的:

async function goToPage() {
  if (session && !hasExpired) {
    navigation.replace('Dashboard')
  } else {
    await removeUserInfo()
    generalDispatch({ type: 'setUser', payload: { userPayload: null } });
    navigation.replace('Welcome')
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.