当我在 Expo Go 上测试我的应用程序时,我完全没有收到任何错误,并且我的应用程序运行良好。在创建构建时,当我尝试登录并单击登录按钮时,应用程序突然进入 SplashScreen。注册页面上也会发生同样的情况。我已经能够推断出异步请求会触发此问题。也就是说,我仍然不知道如何去做。这特别难以调试,因为它只出现在 APK 版本中。我正在使用 expo 和 expo 路由器。
app/index.tsx(登录页面)
import loginApi from "@/api/login";
import { useAuthContext } from "@/auth/context";
import { ThemedText } from "@/components/ThemedText";
import AppForm from "@/components/forms/AppForm";
import AppFormField from "@/components/forms/AppFormField";
import SubmitButton from "@/components/forms/SubmitButton";
import { Colors } from "@/constants/Colors";
import useApi from "@/hooks/useApi";
import Constants from "expo-constants";
import { Link } from "expo-router";
import { X } from "lucide-react-native";
import { useState } from "react";
import { ActivityIndicator, Image, StyleSheet, Text, View } from "react-native";
import * as Yup from "yup";
import * as SplashScreen from 'expo-splash-screen';
export interface UserCredentials {
email: string;
password: string;
}
export default function index() {
const { login,showNotification } = useAuthContext();
const [loginFailed, setLoginFailed] = useState<boolean>(false);
const validationSchema = Yup.object().shape({
email: Yup.string().required().email().label("Email"),
password: Yup.string().required().min(4).label("Password"),
});
const {
loading,
request: loginRequest,
} = useApi(loginApi.getLogin);
const handleSubmit = async({ email, password }: UserCredentials) => {
const data = { email, password };
setLoginFailed(false);
try {
const response = await loginRequest(data);
SplashScreen.hideAsync()
if (response && response.status === 200) {
login(response.data);
} else {
SplashScreen.hideAsync()
console.log(response.data.non_field_errors);
showNotification(`Login failed. ${response.data.non_field_errors[0]}`, <X size={16} color="red" fill={"red"} />);
setLoginFailed(true);
}
} catch (error: any) {
if (error.response && error.response.data) {
const nonFieldErrors = error.response.data.non_field_errors;
if (nonFieldErrors && nonFieldErrors.length > 0) {
showNotification(nonFieldErrors[0], <X size={16} color="red" fill={"red"} />);
} else {
showNotification(`Login failed. Please try again. ${error.response.data}`, <X size={16} color="red" fill={"red"} />);
}
} else {
showNotification(`Login failed. Please try again. ${error.message}`, <X size={16} color="red" fill={"red"} />);
}
setLoginFailed(true);
}
};
return (
<View style={styles.Screen}>
<View style={styles.Top}>
<Image
source={require("../assets/images/HopterlinkLogo.png")}
style={{ width: 150, height: 150, marginTop: 50 }}
resizeMethod="resize"
resizeMode="contain"
/>
</View>
<View style={{ paddingTop: 30 }}>
<ThemedText
darkColor="#000000"
type="title"
style={{ fontSize: 20, fontWeight: "800" }}
>
Sign In
</ThemedText>
<View>
<AppForm
initialValues={{ email: "", password: "" }}
onSubmit={handleSubmit}
validationSchema={validationSchema}
>
<AppFormField
name="email"
icon="mail"
style={{ marginTop: 10 }}
placeholder="Email"
keyboardType="email-address"
/>
<AppFormField
name="password"
icon="lock"
style={{ marginTop: 10 }}
placeholder="Password"
secureTextEntry={true}
/>
<Text
style={{
color: Colors.primary,
textAlign: "right",
marginTop: 10,
fontWeight: "bold",
fontSize: 12,
}}
>
Forgot Password?
</Text>
{loading ? (
<View>
<ActivityIndicator color={Colors.primary} size={"small"} style={{ marginVertical: 20 }} />
</View>
) : (
<SubmitButton title="Sign In" />
)}
</AppForm>
{loginFailed && (
<Text style={{ color: 'red', textAlign: 'center', marginTop: 10 }}>
Login failed. Please try again.
</Text>
)}
</View>
</View>
<View style={{ marginTop: 20 }}>
<Text
style={{
color: "rgba(166, 166, 166, 0.6)",
textAlign: "center",
marginTop: 10,
fontWeight: "bold",
fontSize: 14,
}}
>
Don’t have an account?{" "}
<Link style={{ color: Colors.primary }} href="/sign-up">
Sign Up
</Link>
</Text>
<View>
<Text
style={{
marginTop: 20,
textAlign: "center",
fontWeight: "bold",
fontSize: 14,
}}
>
Social Login
</Text>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
Screen: {
flex: 1,
backgroundColor: Colors.light.background,
paddingHorizontal: 10,
paddingTop: Constants.statusBarHeight,
},
Top: {
flex: 0.5,
alignItems: "center",
justifyContent: "center",
},
button: {
width: "100%",
padding: 15,
marginTop: 40,
backgroundColor: Colors.primary,
borderRadius: 10,
justifyContent: "center",
alignItems: "center",
marginVertical: 10,
},
});
应用程序/_layout.tsx
import { AuthProvider, useAuthContext } from "@/auth/context";
import OfflineNotice from "@/components/OfflineNotice";
import { Colors } from "@/constants/Colors";
import { BottomSheetProvider } from "@/contexts/BottomSheetContext";
import { useFonts } from "expo-font";
import {Stack, useRouter, useSegments } from "expo-router";
import { useEffect } from "react";
import { ActivityIndicator, View } from "react-native";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import * as SplashScreen from 'expo-splash-screen';
SplashScreen.preventAutoHideAsync();
const InitialLayout = () => {
const [loaded, error] = useFonts({
SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
Proxima: require("../assets/fonts/Proxima-Nova-Font.otf"),
SFProBold: require("../assets/fonts/SFPRODISPLAYBOLD.otf"),
SFProMedium: require("../assets/fonts/SFPRODISPLAYMEDIUM.otf"),
SFProRegular: require("../assets/fonts/SFPRODISPLAYREGULAR.otf"),
});
const { user } = useAuthContext();
const segments = useSegments();
const router = useRouter();
useEffect(() => {
if (error) throw error;
}, [error]);
useEffect(() => {
if (loaded) {
SplashScreen.hideAsync();
}
}, [loaded]);
useEffect(() => {
setTimeout(() => {
const inAuthGroup = segments[0] === "(app)";
if (user && !inAuthGroup) {
router.replace("/(app)/(tabs)/(home)/home");
} else if (!user) {
router.replace("/");
}
}, 500);
}, [user]);
// Conditional rendering based on font loading and user state
if (!loaded) {
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<ActivityIndicator size="large" color={Colors.primary} />
</View>
);
}
return (
<Stack>
<Stack.Screen
name="index"
options={{
presentation:"transparentModal",
headerShown: false,
}}
/>
{/* <Stack.Screen name="login" options={{ headerShown: false }} /> */}
<Stack.Screen name="sign-up" options={{ headerShown: false }} />
<Stack.Screen name="verification" options={{ headerShown: false }} />
<Stack.Screen name="(app)" options={{ headerShown: false }} />
</Stack>
);
};
const RootLayoutNav = () => {
return (
<AuthProvider>
<GestureHandlerRootView style={{ flex: 1 }}>
<OfflineNotice />
<BottomSheetProvider>
<InitialLayout />
</BottomSheetProvider>
</GestureHandlerRootView>
</AuthProvider>
);
};
export default RootLayoutNav;
应用程序表格
import React from "react";
import { StyleSheet } from "react-native";
import {
Formik
} from 'formik';
interface AppFormProps {
initialValues: any;
onSubmit: (values: any) => void;
validationSchema: any;
children: React.ReactNode;
}
const AppForm = ({ initialValues, onSubmit, validationSchema, children }:AppFormProps) => {
return (
<Formik
initialValues={initialValues}
onSubmit={onSubmit}
validationSchema={validationSchema}
>
{() => <>{children}</>}
</Formik>
);
}
export default AppForm;
System:
OS: Windows 11 10.0.22631
Binaries:
Node: 19.7.0 - C:\Program Files\nodejs\node.EXE
npm: 9.5.0 - C:\Program Files\nodejs\npm.CMD
IDEs:
Android Studio: AI-241.18034.62.2411.12169540
npmPackages:
expo: ~51.0.31 => 51.0.31
expo-router: ~3.5.23 => 3.5.23
react: 18.2.0 => 18.2.0
react-dom: 18.2.0 => 18.2.0
react-native: 0.74.5 => 0.74.5
react-native-web: ~0.19.10 => 0.19.12
Expo Workflow: managed
我已经注释掉了部分代码,并发现错误发生在await函数上。我尝试使用splashscreen.hideasync()手动删除SplashScreen,但仍然面临问题。我尝试使用 apisauce 手动发出请求,而不将数据传递到函数中,只是在函数中简单发送请求,但错误仍然存在。我尝试输入错误的凭据,按钮仅显示活动指示器,然后闪屏再次弹出,并无限地停留在那里,就像我输入正确的凭据时一样。
您可以在哪里解决这个问题,因为我目前也遇到同样的事情。