作为 ReactJS 的初学者,试图构建一个 React-Native 应用程序,我发现博览会是一个不错的选择。但由于某种原因,我无法从
documentation中找到使用
expo-router
的好方法。
我不太确定需要多少信息才能获得任何帮助,但我将首先写下我的文件夹结构,然后是屏幕的外观。最后我也会写下部分代码。如果此问题还需要任何其他信息,请告诉我。
我的文件夹结构如下所示:
app/
├── settings/
│ ├── _layout.tsx
│ ├── index.tsx
│ └── auth/
│ ├── _layout.tsx
│ ├── index.tsx
│ ├── login.tsx
│ └── signup.tsx
├── _layout.tsx
├── [missing].tsx
├── chat.tsx
└── index.tsx
由于
expo-router
是一个基于文件的路由系统,我希望屏幕像Home -> Settings -> Auth
一样堆叠,但是当我从Home
屏幕转到Settings
页面,然后从那里移动到Auth
时页面,不知何故后退按钮仍然带我回到 Home
屏幕而不是 Settings
页面。
仅供参考,这是我的
Home
页面:
从那里,我单击右上角的按钮(
Settings
页面的标题栏)移动到 Home
页面,如下所示:
如果我点击
Login / Signup
按钮,我们会转到第三页Auth
,但后退按钮仍然显示Home Page
。它看起来像这样:
我的
app/_layout.tsx
看起来像:
import { Stack, router } from "expo-router";
import { ThemeProvider, DefaultTheme, DarkTheme } from "@react-navigation/native";
import { StatusBar, useColorScheme } from "react-native";
import { SettingsButton } from "../src/components";
export default function HomePageLayout() {
const colorScheme = useColorScheme();
return (
<ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
<StatusBar barStyle="default" />
<Stack
screenOptions={{ headerShown: false, headerTintColor: "white", headerStyle: { backgroundColor: "black" }, headerTitleStyle: { fontWeight: "bold" } }}
>
<Stack.Screen
name="index"
options={{
title: "Home Page", headerShown: true, headerRight: () => (
<SettingsButton
color="white"
onPressFunction={() => router.push("settings")}
/>
),
}}
/>
<Stack.Screen
name="settings"
options={{ title: "Settings", headerShown: true }}
/>
<Stack.Screen
name="[missing]"
options={{ title: "Page Not Found", headerShown: true }}
/>
</Stack>
</ThemeProvider>
);
}
我的
app/index.tsx
看起来像这样:
import { Stack, router } from "expo-router";
import { View } from "react-native";
import { CustomButton, bodyStyles } from "../src/components/";
export default function App() {
return (
<>
<View style={[bodyStyles.container, { width: "100%" }]}>
<View style={bodyStyles.buttonContainer}>
<CustomButton
buttonTitle="Chat"
onPressFunction={() => console.log("Chat pressed")}
/>
</View>
</View>
</>
);
}
settings/_layout.tsx
:
import { Stack } from "expo-router";
export default function SettingsLayout() {
return (
<Stack>
<Stack.Screen name="index" options={{ headerShown: false }} />
<Stack.Screen name="auth" options={{ headerShown: false }} />
</Stack>
);
}
settings/index.tsx
:
import React from "react";
import { View } from "react-native";
import { router } from "expo-router";
import { bodyStyles, CustomButton } from "../../src/components";
export default function SettingsScreen() {
return (
<View style={[bodyStyles.container, bodyStyles.buttonContainer]}>
<CustomButton
buttonTitle="Login / Signup"
onPressFunction={() => router.push("/settings/auth")}
/>
</View>
);
}
settings/auth/_layout.tsx
:
import { Stack } from "expo-router";
export default function AuthLayout() {
return (
<Stack>
<Stack.Screen name="index" options={{ headerShown: false }} />
<Stack.Screen name="login" options={{ headerShown: false, presentation: "modal" }} />
<Stack.Screen name="signup" options={{ headerShown: false, presentation: "modal" }} />
</Stack>
);
}
settings/auth/index.tsx
:
import React from "react";
import { View, Text } from "react-native";
import { CustomButton, bodyStyles } from "../../../src/components";
import { router } from "expo-router";
export default function AuthScreen() {
return (
<View style={bodyStyles.container}>
<Text style={bodyStyles.header1}>Welcome user!!</Text>
<Text style={bodyStyles.header2}>Please login or create account!</Text>
<View style={bodyStyles.buttonContainer}>
<LoginButton />
<SignupButton />
<CustomButton
buttonTitle="Go Back"
onPressFunction={() => router.back()}
/>
</View>
</View>
);
}
在最后一页上,当我按下
router.back()
按钮时调用 Go Back
时,我会转到 Settings
页面。这应该意味着堆栈上的最后一个屏幕是 Settings
页面,而不是 Home Page
,但后退按钮仍然设置为 Home Page
页面中的 Auth
。
我已经提供了我认为必要的尽可能多的背景信息。请让我知道我做错了什么。另外,如果我没有遵循 React-Native 应该遵循的任何最佳实践,请随时告诉我。
提前谢谢您!
编辑:我意识到,如果我将屏幕的
headerShown: true
选项放在 settings/_layout
或 auth/_layout
下,我会得到另一个级别的标题,该标题将返回到 Settings
页面。这意味着,每次我在 <Stack>
中调用另一层 _layout.tsx
时,它只会在我的屏幕所在位置创建一个单独的堆栈。屏幕中最顶部的标题始终指向 Home Page
,因为这是最顶部堆栈上唯一的其他选项。
所以我的问题本质上是,定义充当单个堆栈的嵌套堆栈的理想方法是什么,即使路由是嵌套的?
我找到了一种方法,可以在未出现后退按钮的页面的标题上手动放置后退按钮。
例如,我将
app/settings/_layout.tsx
文件更改为:
import { Stack, router } from "expo-router";
import { Ionicons } from "@expo/vector-icons";
import { Platform } from "react-native";
export default function SettingsLayout() {
const backIcon = Platform.OS === "ios" ? "chevron-back" : "arrow-back-sharp";
return (
<Stack
screenOptions={{
headerShown: true,
headerTintColor: "white",
headerStyle: { backgroundColor: "black" },
headerTitleStyle: { fontWeight: "bold" },
headerBackTitleVisible: false,
}}
>
<Stack.Screen
name="index"
options={{
title: "Settings",
headerLeft: () => (
<Ionicons
name={backIcon}
size={25}
color="white"
onPress={() => router.back()}
/>
),
}}
/>
<Stack.Screen name="auth" options={{ title: "Authorize" }} />
</Stack>
);
}
这为我提供了一个适合所有看起来接近本机解决方案的平台的不错的解决方案。
但作为一个非本地解决方案,它也引入了一些问题。例如,在 Android 中,无论应用非本机解决方案 (
headerLeft
),标题都会显示在非常靠近 headerLeft
按钮的位置。
此解决方案虽然暂时修补了问题,但仍然没有完全解决创建单个屏幕堆栈同时具有多个
_layout.tsx
文件的多个嵌套路由的问题。
我现在发布解决方案,但如果有人有更好的解决方案以本机方式实现相同的后退按钮,请回答这个问题。