了解 Expo Router 使用的基于文件的路由约定。
当在 app 目录下创建一个文件时,它会自动成为 app 中的一个路由。例如,以下文件将创建以下路由:
¥When a file is created in the app directory, it automatically becomes a route in the app. For example, the following files will create the following routes:
app
index.tsx
matches '/'
home.tsx
matches '/home'
[user].tsx
matches dynamic paths like '/expo' or '/evanbacon'
settings
index.tsx
matches '/settings'
¥Pages
页面是通过从应用目录中的文件导出 React 组件作为默认值来定义的。从中导出的文件必须使用 .js
、.jsx
、.tsx
、.ts
扩展名之一。
¥Pages are defined by exporting a React component as the default value from a file in the app directory. The file they are exported from must use one of the .js
, .jsx
, .tsx
, .ts
extensions.
例如,在项目中创建 app 目录,然后在其中创建一个文件 index.tsx。然后,添加以下代码片段:
¥For example, create the app directory in your project and then create a file index.tsx inside it. Then, add the following snippet:
使用 React Native 的 <Text>
组件在任何平台上渲染文本。
¥Render text on any platform with the <Text>
component from React Native.
import { Text } from 'react-native';
export default function Page() {
return <Text>Top-level page</Text>;
}
或者,你可以编写仅限 Web 的 React 组件,例如 <div>
、<p>
等。但是,这些不会在原生平台上渲染。
¥Alternatively, you can write web-only React components such as <div>
, <p>
, and so on. However, these won't render on native platforms.
export default function Page() {
return <p>Top-level page</p>;
}
上面的例子匹配了应用和浏览器中的 /
路由。名为 index 的文件与父目录匹配,并且不添加路径段。例如,app/settings/index.tsx 匹配应用中的 /settings
。
¥The above example matches the /
route in the app and the browser. Files named index match the parent directory and do not add a path segment. For example, app/settings/index.tsx matches /settings
in the app.
¥Platform specific extensions
在 Expo Router3.5.x
中添加了平台特定的扩展。如果你使用的是旧版本的库,请按照 特定于平台的模块 中的说明进行操作。
仅当非平台版本也存在时,Metro 打包器的特定于平台的扩展(例如,.ios.tsx 或 .native.tsx)才在应用目录中受支持。这确保了路由在深度链接的跨平台上是通用的。
¥Metro bundler's platform-specific extensions (for example, .ios.tsx or .native.tsx) are supported in the app directory only if a non-platform version also exists. This ensures that routes are universal across platforms for deep linking.
考虑以下项目结构:
¥Consider the following project structure:
app
_layout.tsx
_layout.web.tsx
index.tsx
about.tsx
about.web.tsx
在上面的文件结构中:
¥In the above file structure:
_layout.web.tsx 文件用作 Web 上的布局,_layout.tsx 用于所有其他平台。
¥_layout.web.tsx file is used as a layout on the web and _layout.tsx is used on all other platforms.
index.tsx 文件用作所有平台的主页。
¥index.tsx file is used as the home page for all platforms.
about.web.tsx 文件用作 Web 的关于页面,about.tsx 文件用于所有其他平台。
¥about.web.tsx file is used as the about page for the web, and the about.tsx file is used on all other platforms.
需要提供没有平台特定扩展的路由文件以确保每个平台都有默认实现。
¥Dynamic routes
动态路由与给定网段级别的任何不匹配路径相匹配。
¥Dynamic routes match any unmatched path at a given segment level.
路由 | 匹配的网址 |
---|---|
app/blog/[slug].tsx | /blog/123 |
app/blog/[...rest].tsx | /blog/123/settings |
优先级高的路由会先于动态路由进行匹配。例如,/blog/bacon
将在 blog/[id].tsx 之前匹配 blog/bacon.tsx。
¥Routes with higher specificity will be matched before a dynamic route. For example, /blog/bacon
will match blog/bacon.tsx before blog/[id].tsx.
可以使用剩余语法 (...
) 在单个路由中匹配多个 slugs。例如,app/blog/[...id].tsx 匹配 /blog/123/settings
。
¥Multiple slugs can be matched in a single route by using the rest syntax (...
). For example, app/blog/[...id].tsx matches /blog/123/settings
.
动态段可在页面组件中作为 React 规则 进行访问。
¥Dynamic segments are accessible as route parameters in the page component.
import { useLocalSearchParams } from 'expo-router';
import { Text } from 'react-native';
export default function Page() {
const { slug } = useLocalSearchParams();
return <Text>Blog post: {slug}</Text>;
}
¥Non-route files
应用目录内的每个文件和子目录都是 _layout
文件或应用中的路由。其他文件(例如组件、钩子、实用程序等)不能放在应用目录中,因为它们既不是屏幕也不是布局文件。
¥Every file and sub-directory inside the app directory is either a _layout
file or a route in your app. Other files, such as components, hooks, utilities, and so on, cannot be placed in the app directory because they are neither screens nor layout files.
app
(home)
_layout.tsx
profile.tsx
/profile
(modal)
_layout.tsx
profile.tsx
/profile
上述示例在两个子目录内将 共享路由 用于 /profile
路由。如果你想创建一个非路由文件(例如,ProfileImageComponent.tsx),由于有两个路由目录,因此找到放置此文件的正确子目录会造成两难境地。这是 "why" Expo Router 不允许非路由文件与路由文件一起存在于应用目录中,因为这会导致项目结构混乱。
¥The above example uses shared routes for the /profile
route inside two sub-directories. If you want to create a non-route file (for example, ProfileImageComponent.tsx), finding the correct sub-directory to place this file creates a dilemma since there are two route directories. This is "why" Expo Router does not allow non-route files to exist with route files inside the app directory because it leads to an unstructured project.
¥Recommended structure
Expo Router 建议按 "feature" 对组件和钩子进行排序,按 "导航模式" 对路由进行排序。虽然这两个概念可以重叠,但有足够的差异来以不同的方式构造它们。此外,路由不可避免地会发生变化。但是,组件通常保留在同一功能集内。将路由分开将简化你的重构。
¥Expo Router recommends sorting components and hooks by "feature" and routes by "navigation pattern". While the two concepts can overlap, there are enough differences to structure them differently. Additionally, routes will inevitably change. However, components generally stay within the same feature set. Keeping routes separate will simplify your refactors.
app
sign-in
sign-out
profile
tasks
components
authentication
tasks
overview
profile
[user]
在上面的示例中,/sign-in
和 /sign-out
都是身份验证路由,并从 components/authentication 文件中共享组件。但是,/profile/[user]
路由很复杂,并且会渲染属于身份验证、配置文件和任务功能的组件。如果你将组件放在应用目录中,则这些组件的归属并不明显。通过将组件与路由分离,你可以创建一个有组织的层次结构,其理念是路由是可重用组件的集合,而组件不属于单个路由。
¥In the above example, both /sign-in
and /sign-out
are authentication routes and share components from the components/authentication file. However, the /profile/[user]
route is complex and renders components that belong to the authentication, profile, and task features. If you place your components within the app directory, it's not obvious where these components belong. By separating components from routes, you create an organized hierarchy with the philosophy that a route is a collection of reusable components, and a component does not belong to an individual route.
另一个项目优化是利用 路径别名。它们使你的路由项目结构保持不可知,因为路由内的导入不再依赖于应用目录结构。这避免了在添加新目录(例如新组)时进行大的 import
语句更改,并防止了冗长的 import
路径。
¥Another project optimization is to utilize path aliases. They keep your routes project structure agnostic, as imports within your routes no longer depend on the app directory structure. This avoids large import
statement changes when adding new directories (such as new groups) and prevents lengthy import
paths.
¥Reserved keywords
Expo Router 建立在 React 导航 之上,它对屏幕参数的命名施加了某些限制。因此,以下单词不能用作 Expo Router 中的动态路由参数:
¥Expo Router is built on top of React Navigation, which imposes certain restrictions on the naming of screen parameters. As a result, the following words cannot be used as dynamic route parameters in Expo Router:
screen
params
key