错误处理和加载状态

编辑页面

了解在使用 Expo Router 时,如何在应用中处理未匹配的路由、错误和加载状态。


For the complete documentation index, see llms.txt. Use this file to discover all available pages.

本指南说明在使用 Expo Router 时,如何处理应用中的未匹配路由、错误和加载状态。

未匹配的路由

原生应用没有服务器,因此从技术上讲并不存在 404。不过,如果你正在通用地实现一个路由器,那么处理缺失路由就很有意义。这会为每个应用自动完成,但你也可以自定义它。

src/app/+not-found.tsx
import { Unmatched } from 'expo-router'; export default Unmatched;

这将渲染默认的 Unmatched。你也可以导出任何你想要渲染的组件来替代它。我们建议提供一个指向 / 的链接,这样用户就可以返回主页。

路由优先级

在 Web 上,文件按以下顺序提供:

  1. public 目录中的静态文件。
  2. app 目录中的标准路由和动态路由。
  3. app 目录中的 API 路由
  4. 未找到路由将最后被提供,并返回 404 状态码。

错误处理

Expo Router 支持细粒度的错误处理,以便在未来启用更具约束性的数据加载策略。

你可以从任意路由中导出一个嵌套的 ErrorBoundary 组件,以便使用 React 错误边界 拦截并格式化组件级错误:

src/app/home.tsx
import { View, Text } from 'react-native'; import { type ErrorBoundaryProps } from 'expo-router'; export function ErrorBoundary({ error, retry }: ErrorBoundaryProps) { return ( <View style={{ flex: 1, backgroundColor: "red" }}> <Text>{error.message}</Text> <Text onPress={retry}>再试一次?</Text> </View> ); } export default function Page() { ... }

当你导出一个 ErrorBoundary 时,该路由将被 React 错误边界包装,效果如下:

Virtual
function Route({ ErrorBoundary, Component }) { return ( <Try catch={ErrorBoundary}> <Component /> </Try> ); }

ErrorBoundary 不存在时,错误将抛给最近的父级 ErrorBoundary,并接受 errorretry 属性。

进行中

React Native 的 LogBox 需要以更不激进的方式呈现,以便在存在错误时进行开发。目前,它会针对 console.errorconsole.warn 显示。但理想情况下,它只应在出现未捕获错误时显示。

使用 Suspense fallback 的加载状态

重要 自定义 suspense fallback 在 SDK 56 及更高版本中可用。

Expo Router 会将每个路由包裹在一个 React Suspense 边界中。你可以从布局文件中导出一个 SuspenseFallback 组件,以自定义任何子路由挂起时显示的加载界面:

src/app/_layout.tsx
import { ActivityIndicator, View } from 'react-native'; import { Stack } from 'expo-router'; export function SuspenseFallback() { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <ActivityIndicator size="large" /> </View> ); } export default function RootLayout() { return <Stack />; }

当多个父级布局定义了 fallback 时,最近的父级优先。

访问路由参数

SuspenseFallback 组件接收 routeparams 属性。你可以使用 params 来为动态路由显示上下文相关的加载状态,例如:

src/app/(app)/_layout.tsx
import { ActivityIndicator, Text, View } from 'react-native'; import { Stack, type SuspenseFallbackProps } from 'expo-router'; export function SuspenseFallback({ params }: SuspenseFallbackProps) { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text>正在加载个人资料 {params.id}...</Text> <ActivityIndicator size="large" /> </View> ); } export default function AppLayout() { return <Stack />; }

限制