Expo 路由
一个适用于 React Native 和 web 应用的基于文件的路由库。
For the complete documentation index, see llms.txt. Use this file to discover all available pages.
expo-router 是一个面向 React Native 和 web 应用的路由库。它通过基于文件的路由系统来实现导航管理,并提供原生导航组件。
了解 Expo Router 的基础知识、导航模式、核心概念等。
重要 在 SDK 56 及更高版本 中,Expo Router 不再支持在应用代码中从外部
@react-navigation/*包导入。请将这些导入重定向到相应的expo-router入口点。运行 codemod 或按照 SDK 55 到 56 迁移指南 更新你的项目。
安装
要在你的项目中使用 Expo Router,你需要先进行安装。请按照 Expo Router 安装指南中的说明操作:
了解如何在你的项目中安装 Expo Router。
在 app 配置中进行配置
如果你正在使用 默认 模板创建新项目,那么 expo-router 的 配置插件 已经在你的 app 配置中设置好了。
Example app.json with config plugin
{ "expo": { "plugins": ["expo-router"] } }
Configurable properties
| Name | Default | Description |
|---|---|---|
root | "app" | 将路由目录从 |
origin | undefined | 公共文件夹中的资源所托管的生产环境 origin URL。在生产环境中,fetch 函数会通过 polyfill 支持来自此 origin 的相对请求。开发环境的 origin 会通过 Expo CLI 开发服务器推断得出。 |
headOrigin | undefined | 一个更具体的 origin URL,用于 |
asyncRoutes | undefined | 启用异步路由(懒加载)。可以是布尔值、字符串( |
platformRoutes | true | 启用或禁用平台特定路由(例如,index.android.tsx 和 index.ios.tsx)。 |
sitemap | true | 启用或禁用自动生成的站点地图 /_sitemap。 |
partialRouteTypes | true | 启用部分类型化路由生成。这使 TypeScript 可以对路由进行类型检查,而无需所有路由都必须是静态已知的。 |
redirects | undefined | 静态重定向规则数组。每条规则应包含 |
rewrites | undefined | 静态重写规则数组。每条规则应包含 |
headers | undefined | 服务器对每个路由响应设置的一组头信息。其值可以是字符串或字符串数组。 |
disableSynchronousScreensUpdates | false | 禁用原生屏幕的同步布局更新。这在某些情况下有助于提升性能。 |
unstable_useServerMiddleware | false | Experimental 通过 |
unstable_useServerDataLoaders | false | Experimental 启用数据加载器支持。目前仅支持 |
unstable_useServerRendering | false | Experimental 启用服务端渲染。与 |
用法
关于核心概念、命名模式、导航布局以及常见导航模式,请从 Router 101 部分开始:
API
| API | 描述 |
|---|---|
| Stack | 栈导航器、工具栏和屏幕组件 |
| Link | 链接和重定向组件 |
| Color | 平台颜色工具 |
| Native Tabs | 原生标签导航 |
| Split View | 分屏布局 |
| UI | 无头标签组件 |
API
import { useRouter, Tabs, Navigator, Slot } from 'expo-router';
Components
Type: React.Element<BadgeProps>
Type: React.Element<ErrorBoundaryProps>
Type: React.Element<Omit<Omit<ExperimentalStackNavigatorProps, 'children' | 'initialRouteName' | 'layout' | 'screenListeners' | 'screenOptions' | 'screenLayout' | 'UNSTABLE_router' | 'UNSTABLE_routeNamesChangeBehavior' | 'id'> & DefaultRouterOptions<string> & { children: ReactNode; layout?: ((props: { state: StackNavigationState<ParamListBase>; navigation: NavigationHelpers<ParamListBase, {}>; descriptors: Record<...>; children: ReactNode; }) => ReactElement<...>) | undefined; ... 4 more ...; UNSTABLE_routeNamesChangeBehavior?: "firstMatch" | ... 1 more ... | undefined; ..., 'children'> & Partial<Pick<Omit<ExperimentalStackNavigatorProps, 'children' | 'initialRouteName' | 'layout' | 'screenListeners' | 'screenOptions' | 'screenLayout' | 'UNSTABLE_router' | 'UNSTABLE_routeNamesChangeBehavior' | 'id'> & DefaultRouterOptions<string> & { children: ReactNode; layout?: ((props: { state: StackNavigationState<ParamListBase>; navigation: NavigationHelpers<ParamListBase, {}>; descriptors: Record<...>; children: ReactNode; }) => ReactElement<...>) | undefined; ... 4 more ...; UNSTABLE_routeNamesChangeBehavior?: "firstMatch" | ... 1 more ... | undefined; ..., 'children'>>>
Renders the new react-native-screens/experimental native stack.
Sibling to Stack. Native-only — on web it falls back to the standard Stack.
Opt-in per navigator: replace <Stack /> with <ExperimentalStack /> in the
specific layout you want to migrate.
Type: React.Element<LabelProps>
Type: React.Element<React.FC>
Root style-reset for full-screen React Native web apps with a root <ScrollView /> should use the following styles to ensure native parity. Learn more.
Type: React.Element<React.FC>
Type: React.Element<Omit<NavigatorProps<any>, 'children'>>
Renders the currently selected content.
There are actually two different implementations of <Slot/>:
- Used inside a
_layoutas theNavigator - Used inside a
Navigatoras the content
Since a custom Navigator will set the NavigatorContext.contextKey to
the current _layout, you can use this to determine if you are inside
a custom navigator or not.
Type: React.Element<SuspenseFallbackProps>
Type: React.Element<VectorIconProps<NameT>>
Helper component for loading vector icons.
Prefer using the md and sf props on Icon rather than using this component directly.
Only use this component when you need to load a specific icon from a vector icon family.
Example
import { Icon, VectorIcon } from 'expo-router'; import MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons'; <Icon src={<VectorIcon family={MaterialCommunityIcons} name="home" />} />
{
getImageSource: (name: NameT, size: number, color: ColorValue) => Promise<ImageSourcePropType | null>
}The family of the vector icon.
Example
import MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons';
Type: React.Element<StackScreenProps>
Type: React.Element<ScreenProps<TabsProps, TabNavigationState<ParamListBase>, BottomTabNavigationEventMap>>
Type: React.Element<StackScreenBackButtonProps>
Component to configure the back button.
Can be used inside Stack.Screen in a layout or directly inside a screen component.
Example
import { Stack } from 'expo-router'; export default function Layout() { return ( <Stack> <Stack.Screen name="detail"> <Stack.Screen.BackButton displayMode="minimal">Back</Stack.Screen.BackButton> </Stack.Screen> </Stack> ); }
Example
import { Stack } from 'expo-router'; export default function Page() { return ( <> <Stack.Screen.BackButton hidden /> <ScreenContent /> </> ); }
Note: If multiple instances of this component are rendered for the same screen, the last one rendered in the component tree takes precedence.
Deprecated: Use
Stack.Titleinstead.
Type: React.Element<StackTitleProps>
Constants
Type: Theme
Type: Theme
Type: {
addListener: (eventType: EventType, callback: (event: Payload<EventType>) => void) => () => void,
emit: (type: EventType, event: Payload<EventType>) => void,
enable: () => void,
isEnabled: () => boolean
}
Hooks
Returns route info for a screen it is called from.
UrlObject | undefined| Parameter | Type | Description |
|---|---|---|
| effect | EffectCallback | Memoized callback containing the effect, should optionally return a cleanup function. |
| do_not_pass_a_second_prop(optional) | undefined | - |
Hook to run an effect whenever a route is focused. Similar to
React.useEffect, but the effect re-runs
each time the screen comes into focus, and the optional cleanup function runs when the
screen loses focus — not on unmount. This makes it the right primitive for refetching
data, restarting subscriptions, or resetting transient screen state every time a user
returns to the route.
The passed callback should be wrapped in React.useCallback
to avoid running the effect too often.
voidExample
import { useFocusEffect } from 'expo-router'; import { useCallback } from 'react'; export default function Route() { useFocusEffect( // Callback should be wrapped in `React.useCallback` to avoid running the effect too often. useCallback(() => { // Invoked whenever the route is focused. console.log("Hello, I'm focused!"); // Return function is invoked whenever the route gets out of focus. return () => { console.log('This route is now unfocused.'); }; }, []), ); return </>; }
Returns URL parameters for globally selected route, including dynamic path segments. This function updates even when the route is not focused. Useful for analytics or other background operations that don't draw to the screen.
Route URL example: acme://profile/baconbrix?extra=info.
When querying search params in a stack, opt-towards using
useLocalSearchParams because it will only update when the route is focused.
Note: For usage information, see Local versus global search parameters.
RouteOutputParams<TRoute> & TParamsExample
import { Text } from 'react-native'; import { useGlobalSearchParams } from 'expo-router'; export default function Route() { // user=baconbrix & extra=info const { user, extra } = useGlobalSearchParams(); return <Text>User: {user}</Text>; }
Hook to get the current focus state of the screen. Returns a true if screen is focused, otherwise false.
This can be used if a component needs to render something based on the focus state.
booleanReturns the result of the loader function for the calling route.
LoaderFunctionResult<T>Example
import { Text } from 'react-native'; import { useLoaderData } from 'expo-router'; export function loader() { return Promise.resolve({ foo: 'bar' }}; } export default function Route() { const data = useLoaderData<typeof loader>(); // { foo: 'bar' } return <Text>Data: {JSON.stringify(data)}</Text>; }
Returns the URL parameters for the contextually focused route. Useful for stacks where you may push a new screen that changes the query parameters. For dynamic routes, both the route parameters and the search parameters are returned.
Route URL example: acme://profile/baconbrix?extra=info.
To observe updates even when the invoking route is not focused, use useGlobalSearchParams.
Note: For usage information, see Local versus global search parameters.
RouteOutputParams<TRoute> & TParamsExample
import { Text } from 'react-native'; import { useLocalSearchParams } from 'expo-router'; export default function Route() { // user=baconbrix & extra=info const { user, extra } = useLocalSearchParams(); return <Text>User: {user}</Text>; }
| Parameter | Type | Description |
|---|---|---|
| parent(optional) | string | HrefObject | Provide an absolute path such as |
Returns the navigation object for the current route. Mirrors the React Navigation
navigation object. Use it to
imperatively access layout-specific functionality like navigation.openDrawer() in a
Drawer layout.
TThe navigation object for the current route.
See: The full navigation API is available directly from
expo-router— no@react-navigation/*install required. For the navigator-dependent functions reference, see navigation dependent functions.
Example
import { useNavigation } from 'expo-router'; export default function Route() { // Access the current navigation object for the current route. const navigation = useNavigation(); return ( <View> <Text onPress={() => { // Open the drawer view. navigation.openDrawer(); }}> Open Drawer </Text> </View> ); }
When using nested layouts, you can access higher-order layouts by passing a secondary argument denoting the layout route.
For example, /menu/_layout.tsx is nested inside /app/orders/, you can use useNavigation('/orders/menu/').
Example
import { useNavigation } from 'expo-router'; export default function MenuRoute() { const rootLayout = useNavigation('/'); const ordersLayout = useNavigation('/orders'); // Same as the default results of `useNavigation()` when invoked in this route. const parentLayout = useNavigation('/orders/menu'); }
If you attempt to access a layout that doesn't exist, an error such as
Could not find parent navigation with route "/non-existent" is thrown.
NavigationContainerRefWithCurrent<RootParamList>The root <NavigationContainer /> ref for the app. The ref.current may be null
if the <NavigationContainer /> hasn't mounted yet.
Returns the currently selected route location without search parameters. For example, /acme?foo=bar returns /acme.
Segments will be normalized. For example, /[id]?id=normal becomes /normal.
stringExample
import { Text } from 'react-native'; import { usePathname } from 'expo-router'; export default function Route() { // pathname = "/profile/baconbrix" const pathname = usePathname(); return <Text>Pathname: {pathname}</Text>; }
Deprecated: Use
useNavigationContainerRefinstead, which returns a Reactref.
NavigationContainerRef<RootParamList> | nullReturns the navigation state of the root navigator — the top-level navigator that contains the current screen.
NavigationStateThe current NavigationState of the root navigator.
See: React Navigation's navigation state reference for the shape of the returned object.
Example
import { useRootNavigationState } from 'expo-router'; export default function Route() { const { routes } = useRootNavigationState(); return <Text>{routes[0].name}</Text>; }
Hook to access the route prop of the parent screen anywhere.
TRoute prop of the parent screen.
Hook to get the path for the current route based on linking options.
string | undefinedPath for the current route.
Returns the Router object for imperative navigation.
ImperativeRouterExample
import { useRouter } from 'expo-router'; import { Text } from 'react-native'; export default function Route() { const router = useRouter(); return ( <Text onPress={() => router.push('/home')}>Go Home</Text> ); }
Returns a list of selected file segments for the currently selected route. Segments are not normalized,
so they will be the same as the file path. For example, /[id]?id=normal becomes ["[id]"].
RouteSegments<TSegments>Example
import { Text } from 'react-native'; import { useSegments } from 'expo-router'; export default function Route() { // segments = ["profile", "[user]"] const segments = useSegments(); return <Text>Hello</Text>; }
useSegments can be typed using an abstract. Consider the following file structure:
- app - [user] - index.tsx - followers.tsx - settings.tsx
This can be strictly typed using the following abstract with useSegments hook:
const [first, second] = useSegments<['settings'] | ['[user]'] | ['[user]', 'followers']>()
Returns the server document data for server-side rendering, including <html>/<body>
attributes and additional nodes to add to <head>/<body> for metadata and assets.
ServerDocumentDataExample
import { useServerDocumentContext } from 'expo-router/html'; export default function Root({ children }) { const { htmlAttributes, bodyAttributes, headNodes, bodyNodes } = useServerDocumentContext(); return ( <html {...htmlAttributes}> <head>{headNodes}</head> <body {...bodyAttributes}> {children} {bodyNodes} </body> </html> ); }
SitemapType | nullThemeMethods
| Parameter | Type | Description |
|---|---|---|
| Nav | T | The navigator component to wrap. |
| processor(optional) | (options: ScreenProps[]) => ScreenProps[] | A function that processes the screens before passing them to the navigator. |
| useOnlyUserDefinedScreens(optional) | boolean | If true, all screens not specified as navigator's children will be ignored. Default: false |
Returns a navigator that automatically injects matched routes and renders nothing when there are no children.
Return type with children prop optional.
Enables use of other built-in React Navigation navigators and other navigators built with the React Navigation custom navigator API.
Component<PropsWithoutRef<PickPartial<ComponentProps<T>, 'children'>>> & {
Protected: FunctionComponent<ProtectedProps>,
Screen: (props: ScreenProps<TOptions, TState, TEventMap>) => null
}Example
import { ParamListBase, TabNavigationState } from "@react-navigation/native"; import { createMaterialTopTabNavigator, MaterialTopTabNavigationOptions, MaterialTopTabNavigationEventMap, } from "@react-navigation/material-top-tabs"; import { withLayoutContext } from "expo-router"; const MaterialTopTabs = createMaterialTopTabNavigator(); const ExpoRouterMaterialTopTabs = withLayoutContext< MaterialTopTabNavigationOptions, typeof MaterialTopTabs.Navigator, TabNavigationState<ParamListBase>, MaterialTopTabNavigationEventMap >(MaterialTopTabs.Navigator); export default function TabLayout() { return <ExpoRouterMaterialTopTabs />; }
Interfaces
| Property | Type | Description |
|---|---|---|
| actionType | string | The action type from the dispatched NavigationAction (e.g. |
| payload | object | undefined | - |
| state | ReactNavigationState | - |
| type | 'actionDispatched' | - |
Extends: BasePageEvent
The page rendered as part of a preload (e.g. router.prefetch()) and is not
currently focused. If the user later navigates to this route, the matching
pageFocused will fire then; the preload may also be invalidated or the
route unmounted (pageRemoved) without a focus.
| Property | Type | Description |
|---|---|---|
| type | 'pagePreloaded' | - |
Types
Literal Type: union
Acceptable values are: PagePreloadedEvent | PageFocusedEvent | PageBlurredEvent | PageRemoved | ActionDispatchedEvent
Memoized callback containing the effect, should optionally return a cleanup function.
undefined | void | () => void
Navigator-level events emitted by ExperimentalStack. Mirrors the subset of
NativeStackNavigationEventMap that the gamma Stack.Screen lifecycle
callbacks can drive.
| Property | Type | Description |
|---|---|---|
| gestureCancel | {
data: undefined
} | - |
| transitionEnd | {
data: {
closing: boolean
}
} | - |
| transitionStart | {
data: {
closing: boolean
}
} | - |
Options accepted by ExperimentalStack screens. Mirrors the narrow option
surface of the gamma <Stack.HeaderConfig> component from
react-native-screens/experimental. Anything outside this shape is dropped
with a __DEV__ warning at runtime.
| Property | Type | Description |
|---|---|---|
| headerBackVisible(optional) | boolean | - |
| headerShown(optional) | boolean | - |
| headerTransparent(optional) | boolean | - |
| title(optional) | string | - |
Literal Type: union
Acceptable values are: NavigationProp<ParamList, RouteName, NavigatorID, StackNavigationState<ParamList>, ExperimentalStackNavigationOptions, ExperimentalStackNavigationEventMap> | StackActionHelpers<ParamList>
Literal Type: union
Acceptable values are: {string}:{string} | //{string}
The main routing type for Expo Router. It includes all available routes with strongly typed parameters. It can either be:
- string: A full path like
/profile/settingsor a relative path like../settings. - object: An object with a
pathnameand optionalparams. Thepathnamecan be a full path like/profile/settingsor a relative path like../settings. The params can be an object of key-value pairs.
An Href can either be a string or an object.
Generic: T
Type: T ? T[href] : string | HrefObject
| Property | Type | Description |
|---|---|---|
| params(optional) | UnknownInputParams | Optional parameters for the route. |
| pathname | string | The path of the route. |
Returns router object for imperative navigation API.
Example
import { router } from 'expo-router'; import { Text } from 'react-native'; export default function Route() { return ( <Text onPress={() => router.push('/home')}>Go Home</Text> ); }
| Property | Type | Description |
|---|---|---|
| back | () => void | Goes back in the navigation history. |
| canDismiss | () => boolean | Checks if it is possible to dismiss the current screen. Returns |
| canGoBack | () => boolean | Navigates to a route in the navigator's history if it supports invoking the |
| dismiss | (count: number) => void | Navigates to the a stack lower than the current screen using the provided count if possible, otherwise 1. If the current screen is the only route, it will dismiss the entire stack. |
| dismissAll | () => void | Returns to the first screen of the closest stack — equivalent to a stack
|
| dismissTo | (href: Href, options: NavigationOptions) => void | Dismisses screens until the provided href is reached. If the href is not found, it will instead replace the current screen with the provided |
| navigate | (href: Href, options: NavigationOptions) => void | Navigates to the provided |
| prefetch | (name: Href) => void | Prefetch a screen in the background before navigating to it |
| push | (href: Href, options: NavigationOptions) => void | Navigates to the provided |
| replace | (href: Href, options: NavigationOptions) => void | Navigates to route without appending to the history. Can be used with
|
| setParams | (params: Partial<RouteInputParams<T>>) => void | Updates the current route's query params. |
Created by using a special file called +native-intent.tsx at the top-level of your
project's app directory. It exports redirectSystemPath or legacy_subscribe functions,
both methods designed to handle URL/path processing.
Useful for re-writing URLs to correctly target a route when unique/referred URLs are incoming from third-party providers or stale URLs from previous versions.
See: For more information on how to use
NativeIntent, see Customizing links.
| Property | Type | Description |
|---|---|---|
| legacy_subscribe(optional) | (listener: (url: string) => void) => undefined | void | () => void |
Useful as an alternative API when a third-party provider doesn't support Expo Router
but has support for React Navigation via Using this API is not recommended for newer projects or integrations since it is incompatible with Server Side Routing and Static Rendering, and can become challenging to manage while offline or in a low network environment. |
| redirectSystemPath(optional) | (event: {
initial: boolean,
path: string
}) => Promise<string | null> | string | null | A special method used to process URLs in native apps. When invoked, it receives an
Its return value should be a Note that throwing errors within this method may result in app crashes. It's recommended to
wrap your code inside a
|
Literal Type: union
The list of input keys will become optional, everything else will remain the same.
| Property | Type | Description |
|---|---|---|
| destination | string | - |
| destinationContextKey | string | - |
| external(optional) | boolean | - |
| methods(optional) | string[] | - |
| permanent(optional) | boolean | - |
| source | string | - |
Literal Type: union
Acceptable values are: ./{string} | ../{string} | '..'
Type: PartialState<NavigationState> extended by:
| Property | Type | Description |
|---|---|---|
| state(optional) | ResultState | - |
Type: Exclude<Extract[pathname], RelativePathString | ExternalPathString>
| Property | Type | Description |
|---|---|---|
| dangerouslySingular(optional) | SingularOptions | - |
| getId(optional) | ({ params }: {
params: Record<string, any>
}) => string | undefined | - |
| initialParams(optional) | Record<string, any> | - |
| listeners(optional) | ScreenListeners<TState, TEventMap> | (prop: {
navigation: any,
route: RouteProp<ParamListBase, string>
}) => ScreenListeners<TState, TEventMap> | - |
| name(optional) | string | Name is required when used inside a Layout component. |
| options(optional) | TOptions | (prop: {
navigation: any,
route: RouteProp<ParamListBase, string>
}) => TOptions | - |
| redirect(optional) | boolean | Redirect to the nearest sibling route.
If all children are |
Type: boolean or object shaped as below:
(name, params) => string | undefined
string | undefined| Parameter | Type | Description |
|---|---|---|
| name(index signature) | string | - |
| params(index signature) | UnknownOutputParams | - |
| Property | Type | Description |
|---|---|---|
| children | SitemapType[] | - |
| contextKey | string | - |
| filename | string | - |
| href | string | Href | - |
| isGenerated | boolean | - |
| isInitial | boolean | - |
| isInternal | boolean | - |