基于文件的路由

了解 Expo Router,它是一个基于文件的路由系统,以及如何在你的项目中使用它。


本指南提供了 Expo Router 和导航模式(堆栈和选项卡)的基本约定和指导。要继续,你可以在现有项目中 使用默认模板创建项目 或安装 Expo Router 库手动

¥This guide provides basic conventions and guidance for Expo Router and navigation patterns (stack and tabs). To follow along, you can create a project by using the default template or install Expo Router library manually in your existing project.

什么是 Expo Router?

¥What is Expo Router?

Expo Router 是用于 React Native 和 Web 应用的路由框架。它允许你管理应用中屏幕之间的导航,并在多个平台(Android、iOS 和 Web)上使用相同的组件。它使用基于文件的方法来确定应用内的路由。它还提供原生导航并建立在 React 导航 之上。

¥Expo Router is a routing framework for React Native and web applications. It allows you to manage navigation between screens in your app and use the same components on multiple platforms (Android, iOS and web). It uses a file-based method to determine routes inside your app. It also provides native navigation and is built on top of React Navigation.

app 目录

¥app directory

该应用是一个特殊目录。你添加到此目录的任何文件都将成为原生应用内的路由,并在网络上反映该路由的相同 URL。

¥The app is a special directory. Any file you add to this directory becomes a route inside the native app and reflects the same URL for that route on the web.

创建路由

¥Create a route

在 app 目录中,通过添加包含 index.tsx 文件的文件或嵌套目录来创建路由。

¥In the app directory, a route is created by adding a file or a nested directory that includes index.tsx file.

例如,要创建应用的初始路由,你可以使用以下代码将 index.tsx 添加到应用目录:

¥For example, to create an initial route of your app, you can add index.tsx to the app directory with the following code:

app/index.tsx
import { View, Text, StyleSheet } from 'react-native';

export default function HomeScreen() {
  return (
    <View style={styles.container}>
      <Text>Home</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

app/index.tsx 文件将与 / 路由匹配,创建此文件后,应用目录结构为:

¥The app/index.tsx file will match the / route and after creating this file the app directory structure is:

app
index.tsxmatches '/'

文件名约定

¥File name conventions

名为 index 的文件与父目录匹配,并且不添加路径段。例如,如果你通过添加 app/settings/index.tsx 来扩展应用的文件结构,它将匹配 /settings 路由。

¥Files named index match the parent directory and do not add a path segment. For example, if you expand the app's file structure by adding app/settings/index.tsx, it will match the /settings route.

app
index.tsxmatches '/'
settings
  index.tsxmatches '/settings'

注意:通过将 React 组件导出为默认值来定义路由文件。该文件必须使用 .js.jsx.ts.tsx 扩展名。

¥Note: A route file is defined by exporting a React component as the default value. The file must use either .js, .jsx, .ts, or .tsx extension.

_layout 文件

¥_layout file

目录中的布局文件用于定义共享 UI 元素(例如标题、标签栏),以便它们在不同路由之间保持不变。

¥Layout files in a directory are used to define shared UI elements such as headers, tab bars so that they persist between different routes.

每次你创建新项目时,默认情况下,应用目录将包含一个根布局文件(app/_layout)。

¥Any time you create a new project, by default the app directory will contain a root layout file (app/_layout).

app
index.tsxmatches '/'
_layoutRoot layout

根布局

¥Root layout

传统上,React Native 项目由单个根组件构成(定义为 App.js 或 index.js)。类似地,应用目录中的第一个布局文件(_layout.tsx)被视为单个根组件。

¥Traditionally, React Native projects are structured with a single root component (defined as App.js or index.js). Similarly, the first layout file (_layout.tsx) inside the app directory is considered to be the single root component.

在多个路由之间,Expo Router 中的 Root 布局文件用于在多个路由之间共享 UI,例如注入全局提供程序、主题、样式、延迟启动画面渲染直到加载资源和字体,或定义应用的根导航结构。

¥Between multiple routes, a Root layout file in Expo Router is used to share UI between multiple routes such as injecting global providers, themes, styles, delay splash screen rendering until assets and fonts are loaded, or defining your app's root navigation structure.

例如,以下代码导出一个名为 RootLayout 的默认 React 组件:

¥For example, the following code exports a default React component called RootLayout:

app/_layout.tsx
export default function RootLayout() {
  return (
	  %%placeholder-start%%... %%placeholder-end%%
  )
}
使用 Expo Router,app/_layout.tsx 中定义的任何 React 提供程序都可以通过应用中的任何路由访问。要提高性能并减少渲染次数,请尝试将提供程序的范围缩小到仅需要它们的路由。

堆栈导航器

¥Stack navigator

堆栈导航器是一种在应用中的不同路由之间导航的模式。它允许在屏幕之间转换并管理导航历史记录。它在概念上类似于 Web 浏览器处理导航状态的方式。

¥A stack navigator is a pattern to navigate between different routes in an app. It allows transitioning between screens and managing the navigation history. It is conceptually similar to how a web browser handles the navigation state.

例如,如果你想添加新路由 /details,请创建 details.tsx 文件。这将允许应用用户从 / 路由导航到 /details

¥For example, if you want to add a new route /details, create details.tsx file. This will allow the app user to navigate from the / route to /details:

app/details.tsx
import { View, Text, StyleSheet } from 'react-native';

export default function DetailsScreen() {
  return (
    <View style={styles.container}>
      <Text>Details</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

创建此路由文件后,当前文件结构如下:

¥After creating this route file, the current file structure looks like:

app
index.tsxmatches '/'
details.tsxmatches '/details'
_layoutRoot layout

要允许在两个路由(//details)之间导航,请更新 Root 布局文件并向其中添加 Stack 组件:

¥To allow navigation between two routes (/ and /details), update the Root layout file and add a Stack component to it:

app/_layout.tsx
import { Stack } from 'expo-router';

export default function RootLayout() {
  return (
    <Stack
      screenOptions={{
        headerStyle: {
          backgroundColor: '#f4511e',
        },
        headerTintColor: '#fff',
        headerTitleStyle: {
          fontWeight: 'bold',
        },
      }}>
      <Stack.Screen name="index" />
      <Stack.Screen name="details" />
    </Stack>
  );
}

布局文件中的 <Stack.Screen name={routeName} /> 组件允许在堆栈中定义路由。

¥<Stack.Screen name={routeName} /> component in the layout file allows defining routes in a stack.

注意:上面示例中的 screenOptions 允许为堆栈内的所有路由配置选项。请参阅 静态配置路由选项 了解更多信息。

¥Note: The screenOptions in the above example allows configuring options for all the routes inside a stack. See Statically configure route options for more information.

在路由之间导航

¥Navigating between routes

Expo Router 使用名为 Link 的内置组件在应用中的路由之间移动。这在概念上类似于 Web 使用 <a> 标签和 href 属性的方式。

¥Expo Router uses a built-in component called Link to move between routes in an app. This is conceptually similar to how web works with the <a> tag and the href attribute.

你可以通过从 Expo Router 库导入它,然后将 href 属性与要导航的路由一起传递作为属性的值来使用它。例如,要从 / 导航到 /details,请在 index.tsx 文件中添加 Link 组件:

¥You can use it by importing it from Expo Router library and then passing the href prop with the route to navigate as the value of the prop. For example, to navigate from / to /details, add a Link component in the index.tsx file:

app/index.tsx
import { Link } from 'expo-router';
import { View, Text, StyleSheet } from 'react-native';

export default function HomeScreen() {
  return (
    <View style={styles.container}>
      <Text>Home</Text>
      <Link href="/details">View details</Link>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

Link 如何工作?

¥How does Link work?

Link 默认将子项封装在 <Text> 中。你可以自定义使用不同的按钮组件。

¥Link wraps the children in a <Text> by default. You can customize to use a different button component.

使用 Link 组件封装自定义按钮组件和 asChild 属性,将所有属性转发到 Link 组件的第一个子项。有关 Link 组件的 props 的更多信息,请参阅 在页面之间导航

¥Use the Link component to wrap the custom button component and the asChild prop which forwards all props to the first child of the Link component. For more information on the Link component's props, see Navigate between pages.

群组

¥Groups

创建一个组来组织类似的路由或应用的一部分。每个组都有一个布局文件,分组目录需要在括号 (group) 内命名。

¥A group is created to organize similar routes or a section of the app. Each group has a layout file, and the grouped directory requires a name inside parentheses (group).

例如,你有 //details 路由,它们可以在 app/(home) 目录中分组。这会将文件结构更新为:

¥For example, you have the / and /details routes which can be grouped inside app/(home) directory. This updates the file structure to:

app
_layout.tsxRoot layout
(home)
  index.tsxmatches '/'
  details.tsxmatches '/details'
  _layout.tsxHome layout

你还需要添加 (home)/_layout.tsx,它用于定义 //details 路由的 Stack 导航器。

¥You also need to add (home)/_layout.tsx which is used to define the Stack navigator for / and /details routes.

app/(home)/_layout.tsx
import { Stack } from 'expo-router';

export default function HomeLayout() {
  return (
    <Stack
      screenOptions={{
        headerStyle: {
          backgroundColor: '#f4511e',
        },
        headerTintColor: '#fff',
        headerTitleStyle: {
          fontWeight: 'bold',
        },
      }}>
      <Stack.Screen name="index" />
      <Stack.Screen name="details" />
    </Stack>
  );
}

Root 布局文件也发生了变化,现在包括 (home) 组,该组进一步使用 (home)/index 作为应用的初始路由。

¥The Root layout file also changes and now includes the (home) group which further uses (home)/index as the initial route of the app.

app/_layout.tsx
import { Stack } from 'expo-router';

export default function RootLayout() {
  return (
    <Stack>
      <Stack.Screen name="(home)" />
    </Stack>
  );
}

注意:在上面的例子中,屏幕选项被移动到 (home)/_layout.tsx 文件。这意味着如果你在 Root 布局中向 Stack 导航器添加任何路由,它将不会使用与 Home 布局中的路由相同的屏幕选项。

¥Note: In the above example, the screen options are moved to (home)/_layout.tsx file. This means if you add any route to the Stack navigator inside the Root layout, it will not use the same screen options as the routes inside the Home layout.

标签导航器

¥Tab navigator

选项卡导航器是一种使用选项卡栏在应用的不同部分之间导航的常见模式。Expo Router 提供 Tabs 导航组件。

¥A tab navigator is a common pattern to navigate between different sections of an app using a tab bar. Expo Router provides a Tabs navigation component.

例如,在当前文件结构中,你有两个不同的部分:主页(//details 路由)和设置(/settings 路由)。添加一个特殊目录(tabs),你可以将现有的 Home 路由文件移动到其中并创建一个 settings.tsx。

¥For example, in the current file structure, you have two different sections: Home (/ and /details routes) and Settings (/settings route). Adding a special directory (tabs), you can move the existing Home route files inside it and create a settings.tsx.

app
_layout.tsxRoot layout
(tabs)
  _layout.tsxTab layout
  (home)
   index.tsxmatches '/'
   details.tsxmatches '/details'
   _layout.tsxHome layout
  settings.tsxmatches '/settings'

(选项卡) 内的任何文件或目录都将成为选项卡导航器中的路由。要使用标签栏在不同路由之间切换,你需要在此目录 (tabs)/_layout 中创建布局文件并导出 TabLayout 组件:

¥Any file or directory inside (tabs) becomes a route in the tab navigator. To switch between different routes using the tab bar, you need to create a layout file inside this directory (tabs)/_layout and export a TabLayout component:

app/(tabs)/_layout.tsx
import { Tabs } from 'expo-router';

export default function TabLayout() {
  return (
    <Tabs>
      <Tabs.Screen name="(home)" />
      <Tabs.Screen name="settings" />
    </Tabs>
  );
}

注意:在 TabLayout 中,(home) 的现有 Stack 导航器现已嵌套。

¥Note: In TabLayout, the existing Stack navigator for (home) is now nested.

要使其工作,请通过添加 (tabs) 作为第一条路由来更新 app/_layout.tsx 文件。

¥To make this work, update the app/_layout.tsx file by adding (tabs) as the first route.

app/_layout.tsx
import { Stack } from 'expo-router';

export default function RootLayout() {
  return (
    <Stack>
      <Stack.Screen name="(tabs)" />
    </Stack>
  );
}

未找到路由

¥Not found routes

Expo Router 提供了一个特殊文件 +not-found.tsx,用于处理 404 路由。此路由文件匹配嵌套级别中所有不匹配的路由。

¥Expo Router provides a special file +not-found.tsx which is used to handle routes that are 404s. This route file matches all unmatched routes from a nested level.

在应用目录中创建此文件:

¥Create this file in the app directory:

+not-found.tsx
import { Link, Stack } from 'expo-router';
import { View, StyleSheet } from 'react-native';

export default function NotFoundScreen() {
  return (
    <>
      <Stack.Screen options={{ title: "Oops! This screen doesn't exist." }} />
      <View style={styles.container}>
        <Link href="/">Go to home screen</Link>
      </View>
    </>
  );
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});