This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
将 Expo 路由从 SDK 57 迁移到 SDK 58
了解如何将你的 Expo Router 应用从 SDK 57 迁移到 SDK 58。
SDK 58 改变了 Expo Router 构建导航状态和与导航器集成的方式。使用 Stack、Link 和 useRouter 的应用可能需要做一些调整。导入自 expo-router/react-navigation、访问导航状态或实现自定义路由和导航器的应用则需要更仔细地检查。
🌐 SDK 58 changes how Expo Router builds navigation state and integrates with navigators. Apps that use Stack, Link, and useRouter may need a few changes. Apps that import from expo-router/react-navigation, access navigation state, or implement custom routers and navigators require closer review.
使用以下清单来找出适用于你应用的部分:
🌐 Use the following checklist to find the sections that apply to your app:
- 对于常见的应用迁移,推荐使用
useRouter,将嵌套导航替换为 hrefs,并将initialRouteName移动到unstable_settings。 - 对于网页应用,查看 异步路由默认值,将 导航钩子移出根 HTML,如果使用
web.output: "server",还要注意 服务端渲染的变化。 - 对于高级集成,更新那些派发操作、读取或保存导航状态,或者实现自定义路由和自定义导航器的代码。
- 如果你的应用从那个入口点导入,检查一下 已移除的
expo-router/react-navigationAPI。
信息 本指南涵盖了最有可能需要应用更新的更改。完整的 SDK 58 更改列表请参见
expo-router更新日志。
常见迁徙
🌐 Common migrations
查看服务器渲染行为
🌐 Review server rendering behavior
在 SDK 58 中,web.output: "server" 会在每次请求时渲染 HTML 页面,而不是在导出时预渲染它们。
🌐 In SDK 58, web.output: "server" renders HTML pages on each request instead of prerendering them during export.
要保持 SDK 57 及更早版本中 web.output: "server" 的行为,请在你的 应用配置 中,将 expo-router 配置插件中的 web.output 设置为 "static",并启用 apiRoutes: true:
🌐 To keep the behavior of web.output: "server" from SDK 57 and earlier, set web.output to "static" and enable apiRoutes: true in the expo-router config plugin in your app config:
这结合了预渲染的 HTML 和 API 路由,并且仍然需要一个已部署的服务器。如果想在每次请求时渲染 HTML,请保留 web.output: "server" 并参考服务器渲染指南。
🌐 This combines prerendered HTML with API routes and still requires a deployed server. To render HTML on each request, keep web.output: "server" and follow the server rendering guide.
查看异步路由默认值
🌐 Review async route defaults
在 SDK 58 中,异步路由在 Web 开发和生产环境中默认启用。原生默认设置保持不变,原生生产构建仍然同步加载路由。
🌐 In SDK 58, async routes are enabled by default on web in development and production. Native defaults are unchanged, and native production builds continue to load routes synchronously.
异步路由使用默认的加载回退,而不是从布局中自定义的 SuspenseFallback 导出。如果你的 web 应用依赖自定义回退,请在你的 应用配置 中的 expo-router 配置插件里禁用 web 上的异步路由:
🌐 Async routes use the default loading fallback instead of custom SuspenseFallback exports from layouts. If your web app relies on a custom fallback, disable async routes on web in the expo-router config plugin in your app config:
这恢复了网页上的同步路由加载以及对自定义加载回退的支持。现有的显式 asyncRoutes 设置仍然优先于默认值。有关配置选项和限制,请参见 异步路由。
🌐 This restores synchronous route loading and support for custom loading fallbacks on web. Existing explicit asyncRoutes settings continue to take precedence over the defaults. See Async routes for configuration options and limitations.
在升级或更改 asyncRoutes 后,使用 expo start --clear 或 expo export --clear 清除 Metro 缓存。
🌐 After upgrading or changing asyncRoutes, clear the Metro cache with expo start --clear or expo export --clear.
把导航钩子移出根 HTML
🌐 Move navigation hooks out of the root HTML
在 SDK 58 中,导航钩子,例如 usePathname、useSegments、useLocalSearchParams 和 useRouter,在 app/+html.tsx 的 根 HTML 组件中不再可用。请改为在 app/_layout.tsx 的 根布局 中使用它们。
🌐 In SDK 58, navigation hooks, such as usePathname, useSegments, useLocalSearchParams, and useRouter, no longer work in the root HTML component in app/+html.tsx. Use them in the root layout in app/_layout.tsx instead.
在组件中更喜欢使用 useRouter
🌐 Prefer useRouter in components
对于组件里的基于 href 的导航,优先使用 useRouter() 返回的路由,而不是 useNavigation().navigate() 或模块级别的 router。这个 hook 是绑定到渲染该组件的 Expo Router 根节点上的。
🌐 Prefer the router returned by useRouter() over useNavigation().navigate() or the module-level router for href-based navigation from a component. The hook is bound to the Expo Router root that rendered the component.
模块级别的 router 仍然可用,但它会在第一个路由渲染之前抛出,而且无法区分多个路由根。当你需要使用特定于导航器的 API 时,比如事件、选项或动作分发,继续使用 useNavigation。
🌐 The module-level router is still available, but it throws before the first router render and cannot distinguish between multiple router roots. Continue to use useNavigation when you need navigator-specific APIs, such as events, options, or action dispatching.
useRouter() 包含常用的导航方法,例如 push、navigate、replace、back、dismiss、dismissTo、dismissAll、canGoBack、canDismiss、setParams 和 prefetch。如果缺少某个需要的导航方法,请提交问题。
使用完整的 href 导航
🌐 Navigate with complete hrefs
在 SDK 57 中,React Navigation 可以将 screen、params 和 initial 解释为构建嵌套状态的指令。在 SDK 58 中,它们是普通的用户参数。请改为导航到完整的 href:
🌐 In SDK 57, React Navigation could interpret screen, params, and initial as instructions for building nested state. In SDK 58, they are ordinary user parameters. Navigate to a complete href instead:
查看 在嵌套导航器中导航到屏幕 了解更多示例。
🌐 See Navigate to a screen in a nested navigator for more examples.
在执行式导航中,祖级路由参数也不再被复制到子路由。如果你的应用依赖子路由从父路由接收参数,需要在目标 href 中包含该值。这样,执行式导航就和从深度链接或冷启动打开相同的 href 一致了。
🌐 Ancestor route params are also no longer copied into descendant routes during imperative navigation. If your app relies on a descendant receiving a parameter from its parent route, include the value in the destination href. This makes imperative navigation consistent with opening the same href from a deep link or cold start.
把 initialRouteName 移到 unstable_settings
🌐 Move initialRouteName to unstable_settings
initialRouteName 导航属性已被移除。要在深度链接进入堆栈时添加返回目的地,请从该堆栈的布局中导出 unstable_settings.anchor:
🌐 The initialRouteName navigator prop is removed. To add a back destination when deep linking into a stack, export unstable_settings.anchor from that stack's layout:
信息 不要使用
anchor来选择应用的初始屏幕。启动 URL 决定了屏幕。对于默认的/URL,请使用 index.tsx 路由。详情请参见 核心概念。
Expo Router 现在可以从 URL 构建完整的初始状态。例如,嵌套在标签页中的堆栈会从该堆栈自己的 _layout.tsx 文件中读取设置。在进行命令式导航时,当锚点路由应该插入到目标下方时,传入 { withAnchor: true }。
🌐 Expo Router now builds complete initial state from the URL. For example, a stack nested in tabs reads the setting from that stack's own _layout.tsx file. During imperative navigation, pass { withAnchor: true } when the anchor route should be inserted below the destination.
请查看 路由设置 了解初始路由和锚点行为。
🌐 See Router settings for initial route and anchor behavior.
替换 redirect 和 initialParams
🌐 Replace redirect and initialParams
布局 Screen 的组件不再接受 redirect 或 initialParams。
🌐 Layout Screen components no longer accept redirect or initialParams.
从路由文件渲染一个 Redirect,而不是在屏幕上配置 redirect:
🌐 Render a Redirect from the route file instead of configuring redirect on a screen:
要进行访问控制,可以使用带有 redirectTo 的受保护路由:
🌐 For access control, use a protected route with redirectTo:
在屏幕读取参数的地方,把 initialParams 替换成默认值:
🌐 Replace initialParams with defaults where the screen reads its params:
声明标签页和抽屉屏幕
🌐 Declare tabs and drawer screens
JavaScript 标签页、顶部标签页、抽屉、无头标签页以及原生标签页现在只显示在布局中声明的屏幕。声明每个应该出现在导航器 UI 中的路由:
🌐 JavaScript tabs, top tabs, drawer, headless tabs, and native tabs now show only screens declared in the layout. Declare every route that should appear in the navigator UI:
更新受保护的路由
🌐 Update protected routes
大多数使用受保护路由的应用不需要做出更改。在 SDK 58 中,受保护路由仍然会在它们的导航器中注册。当路由的守卫失败时,它会渲染一个重定向,而不是从路由树中被移除。
🌐 Most apps that use protected routes do not need to make changes. Protected routes remain registered in their navigator in SDK 58. A route whose guard fails renders a redirect instead of being removed from the route tree.
只有当你想控制重定向的目标时,才在导航器的 Protected 组件上设置 redirectTo。如果不设置,Expo Router 会使用导航器的可访问锚点或初始路由,然后再使用它的第一个可访问路由。
🌐 Set redirectTo on the navigator's Protected component only when you want to control the redirect destination. Without it, Expo Router uses the navigator's accessible anchor or initial route, then its first accessible route.
请参见 受保护的路由 了解守卫模式。
🌐 See Protected routes for guard patterns.
替换网页模态框
🌐 Replace web modals
实验性的网页模态实现已被移除。请按照 构建自定义网页模态 来使用自定义导航器渲染模态覆盖。自定义实现可以从 expo-router 导入 NativeStackView 来使用原生堆栈视图。
🌐 The experimental web modal implementation is removed. Follow Build custom web modals to render modal overlays with a custom navigator. Custom implementations can import NativeStackView from expo-router for the native stack view.
替换 freezeOnBlur
🌐 Replace freezeOnBlur
freezeOnBlur 选项在 SDK 58 中不起作用。请从你的屏幕配置中移除它。要在屏幕失去焦点后清理效果时保留状态,可以在导航器或已声明的屏幕上设置 activityEnabled。设置 1 的值会在另一屏幕获得焦点时立即隐藏屏幕内容:
🌐 The freezeOnBlur option has no effect in SDK 58. Remove it from your screen configuration. To preserve state while cleaning up effects after a screen loses focus, set activityEnabled on the navigator or a declared screen. A value of 1 hides the screen content as soon as another screen is focused:
当 activityEnabled 是 true 时,当某个屏幕上方有两个屏幕时,堆栈会隐藏该屏幕的内容。标签页和抽屉一旦失去焦点就会隐藏屏幕内容。堆栈导航器和屏幕也可以接受一个正数来覆盖这个阈值。
🌐 When activityEnabled is true, a stack hides a screen's content once two screens sit above that screen. Tabs and drawers hide a screen's content as soon as it loses focus. Stack navigators and screens also accept a positive number to override that threshold.
如果只想隐藏屏幕的一部分,请改用将该内容封装在 NavigationAwareActivity 中。它的 hideWhenNestedAtLevel 属性使用相同的阈值行为,默认值是 2。
🌐 To hide only part of a screen, wrap that content in NavigationAwareActivity instead. Its hideWhenNestedAtLevel prop uses the same threshold behavior and defaults to 2.
安装可选的本地依赖
🌐 Install optional native dependencies
SDK 58 让 expo-symbols 和 @expo/ui 成为 Expo Router 的可选对等依赖。只安装你的应用使用的 API 所需要的依赖:
🌐 SDK 58 makes expo-symbols and @expo/ui optional peer dependencies of Expo Router. Install only the dependency required by the APIs your app uses:
在安装任一依赖后,重新构建使用受影响原生 API 的开发版本。
🌐 After installing either dependency, rebuild development builds that use the affected native API.
防止屏幕被移除
🌐 Prevent a screen from being removed
现有的 usePreventRemove 调用只有在它们的回调重复或替代被阻止的动作时才需要更改。要继续执行原本被阻止的动作,将防止条件设置为 false,然后调用回调的 repeat 函数。
🌐 Existing usePreventRemove calls only need changes when their callback repeats or replaces the blocked action. To continue the exact blocked action, set the prevention condition to false and call the callback's repeat function.
当屏幕有未保存的数据时,使用 expo-router 中的 usePreventRemove 来阻止移除:
🌐 Use usePreventRemove from expo-router to block removal while a screen has unsaved data:
要导航到被屏蔽目的地以外的地方,保留由 usePreventRemove 返回的 disablePrevention 函数。将阻止条件设置为 false,调用 disablePrevention(),然后进行导航。在阻止仍然生效时,不要从原始的 removePrevented 监听器中分发操作,因为该动作可能会再次被阻止。
🌐 To navigate somewhere other than the blocked destination, retain the disablePrevention function returned by usePreventRemove. Set the prevention condition to false, call disablePrevention(), and then navigate. Do not dispatch from a raw removePrevented listener while prevention is still active because the action can be blocked again.
警告 在调用
disablePrevention()时,务必更新传给usePreventRemove的布尔值。如果它保持为true,hook 会发出警告,并且在布尔值改变之前不会重新启用防护。
高级迁移
🌐 Advanced migrations
更新 navigation.dispatch
🌐 Update navigation.dispatch
navigation.dispatch 和导航助手动作现在会排队,直到当前的 React 提交之后再执行。只有在集成必须立即执行某个动作时才使用 navigation.dispatchSync(action)。
不再支持派发函数了。先读取状态,计算一个动作,然后派发动作对象:
🌐 Dispatch functions are no longer supported. Read the state first, compute an action, and dispatch the action object:
读取和延迟调度不是原子的。如果在它们之间不能执行其他导航操作,就刻意使用 dispatchSync(action)。
🌐 The read and deferred dispatch are not atomic. Use dispatchSync(action) deliberately if other navigation work cannot happen between them.
替换 navigationKey
🌐 Replace navigationKey
布局 Screen 和 Group 组件不再接受 navigationKey。没有直接的替代方式。根据使用该键的原因,可以使用路由和布局标识、受保护的路由,或者明确的 href 导航。
🌐 Layout Screen and Group components no longer accept navigationKey. There is no direct replacement. Use route and layout identity, protected routes, or explicit href navigation based on why the key was used.
替换 beforeRemove 和 __unsafe_action__
🌐 Replace beforeRemove and __unsafe_action__
beforeRemove 和 __unsafe_action__ 事件已被移除。使用 removed 可以观察到完全移除,使用 removePrevented 可以观察到被 usePreventRemove 阻止的动作。
🌐 The beforeRemove and __unsafe_action__ events are removed. Use removed to observe a completed removal and removePrevented to observe an action blocked by usePreventRemove.
removed 事件在路由卸载后触发。推迟清理它的监听器,以便它能接收到该事件:
🌐 The removed event fires after the route unmounts. Defer cleanup of its listener so it can receive that event:
useEffect(() => { const unsubscribe = navigation.addListener('removed', event => { logRemoval(event.data.action); }); return () => queueMicrotask(unsubscribe); }, [navigation]);
别从这个监听器更新已移除屏幕的状态,因为屏幕已经卸载了。
🌐 Do not update the removed screen's state from this listener because the screen has already unmounted.
把 useNavigation 移到导航器里
🌐 Move useNavigation inside a navigator
useNavigation 现在在导航器外部调用时会抛出错误。如果你手动渲染 ExpoRoot,这包括其 wrapper 属性渲染的组件。把这个钩子移到导航树内部渲染的路由或布局里。
读取导航状态
🌐 Read navigation state
导航状态是一个实现细节。当你需要 URL 或路由信息时,最好使用 usePathname、useSegments 和 useGlobalSearchParams。
🌐 Navigation state is an implementation detail. Prefer usePathname, useSegments, and useGlobalSearchParams when you need URL or route information.
处理可选的 type 和 history
🌐 Handle optional type and history
自定义路由中,导航状态 type 是可选的。在标签和抽屉状态中,history 是可选的。在读取它们之前添加备用值:
🌐 The navigation state type is optional for custom routers. history is optional in tab and drawer state. Add fallback values before reading them:
const history = state.history ?? []; if (state.type === 'tab') { // Handle tab-specific state. }
从 routes 读取堆栈预加载路由
🌐 Read stack preloaded routes from routes
StackNavigationState.preloadedRoutes 已被移除。预加载的路由会在聚焦索引后追加到 state.routes:
const activeRoutes = state.routes.slice(0, state.index + 1); const preloadedRoutes = state.routes.slice(state.index + 1);
使用 routeNames 来设置标签顺序
🌐 Use routeNames for tab order
TabNavigationState.preloadedRouteKeys 已被移除。预加载标签是在 state.routes 中未聚焦的条目,带有 isPreloaded: true,而延迟加载的路由可能不在该数组中。当你需要声明的标签顺序时,遍历 state.routeNames:
for (const routeName of state.routeNames) { const route = state.routes.find(route => route.name === routeName); // `route` is undefined when the lazy route has not been created. }
移除抽屉 default
🌐 Remove drawer default
DrawerNavigationState.default 已被移除。在组件中,使用 expo-router/drawer 的 useDrawerStatus 来读取抽屉是打开还是关闭。getDrawerStatusFromState 已不推荐使用,现在需要将路由的默认状态作为第二个参数。
把 routeKeySeq 包含在完整状态中
🌐 Include routeKeySeq in complete state
持久化的初始状态必须完整。每个嵌套状态都需要一个状态键、路由键、routeKeySeq、routeNames、index 和 stale: false。当 Expo Router 收到不完整的持久化初始状态时会报错。
🌐 Persisted initial state must be complete. Every nested state needs a state key, route keys, routeKeySeq, routeNames, index, and stale: false. Expo Router throws when it receives incomplete persisted initial state.
自定义路由扩展返回的导航状态仍然包含 routeKeySeq,但该扩展不会直接更新它。用 ...state 保留当前状态,并使用 extendRouter 提供的 nextKey 函数。封装器会把更新后的序列写入返回的状态中。
🌐 Navigation state returned by a custom router extension still contains routeKeySeq, but the extension does not update it directly. Preserve the current state with ...state and use the nextKey function provided by extendRouter. The wrapper writes the updated sequence into the returned state.
CommonActions.reset 同样需要 stale: false 的状态,但路由会生成省略的路由键,并从当前状态填充省略的 routeKeySeq。
使用 ...state 来在重置状态时保留当前导航器的键、路由名称和键序列。查看 更新 navigation.dispatch 中的示例。
🌐 Use ...state to preserve the current navigator's keys, route names, and key sequence when resetting its state. See the example in Update navigation.dispatch.
持久状态必须在每个嵌套层级保留有效的键和路由名称。
🌐 Persisted state must retain valid keys and route names at every nested level.
更新自定义路由
🌐 Update custom routers
在 SDK 58 中,可以通过用 extendRouter 或 extendRouterActions 扩展 StackRouter 或 TabRouter 来创建自定义路由。Expo Router 会构建完整的初始状态,而这个封装器则会保留基础路由的行为和状态不可变性。
🌐 In SDK 58, create custom routers by extending StackRouter or TabRouter with extendRouter or extendRouterActions. Expo Router builds the complete initial state, while the wrapper preserves the base router's behavior and state invariants.
更新路由接口
🌐 Update the router interface
把现有自定义路由中与基础路由不同的部分移到一个扩展里。扩展没有重写的成员会被继承:
🌐 Move the parts of an existing custom router that differ from its base router into an extension. Members that the extension does not override are inherited:
基础堆栈和标签路由处理 PUSH。如果一个扩展覆盖了 getStateForAction,就将它不处理的操作委托给提供的 baseRouter。
🌐 The base stack and tab routers handle PUSH. If an extension overrides getStateForAction, delegate actions that it does not handle to the provided baseRouter.
返回受影响的路由键
🌐 Return the affected route key
getStateForAction 现在会返回下一个状态,同时返回受该操作影响的路线键:
将 affectedRouteKey 设置为由特定操作选择或更改的路由,这不总是当前聚焦的路由。当路由无法处理某个操作时,返回 null。
🌐 Set affectedRouteKey to the route selected or changed by that specific action, which is not always the focused route. Return null when the router cannot handle an action.
扩展内置路由
🌐 Extend a built-in router
extendRouter 接收基础路由和一个 nextKey 函数。nextKey 生成确定性的路由键,封装器将更新后的 routeKeySeq 写入返回的状态中:
import { attachRouteState, extendRouter, StackRouter, type CommonNavigationAction, type StackActionType, } from 'expo-router'; type CustomAction = { type: 'CUSTOM-ACTION'; payload: { name: string; params?: object }; }; const CustomStackRouter = extendRouter(StackRouter, ({ baseRouter, nextKey }) => ({ getStateForAction( state, action: CommonNavigationAction | StackActionType | CustomAction, config ) { if (action.type === 'CUSTOM-ACTION') { if (!state.routeNames.includes(action.payload.name)) { return null; } const route = attachRouteState( { key: nextKey(action.payload.name), name: action.payload.name, params: action.payload.params, }, action ); const activeRoutes = state.routes.slice(0, state.index + 1); const preloadedRoutes = state.routes.slice(state.index + 1); return { state: { ...state, index: activeRoutes.length, routes: [...activeRoutes, route, ...preloadedRoutes], }, affectedRouteKey: route.key, }; } return baseRouter.getStateForAction(state, action, config); }, }));
当只需要自定义 getStateForAction 时使用 extendRouterActions。从它的 reducer 返回 undefined 来委托一个动作。当用 extendRouter 覆盖 getStateForAction 时,将未处理的动作委托给 baseRouter,如上所示。
🌐 Use extendRouterActions when only getStateForAction needs customization. Return undefined from its reducer to delegate an action. When overriding getStateForAction with extendRouter, delegate unhandled actions to baseRouter as shown above.
在合适的时候把路由类型设为可选
🌐 Make the router type optional when appropriate
extendRouter 继承了基础路由的 type。如果扩展将状态更改为需要不同类型,可以在封装器的选项中传入该类型。状态类型可选的扩展可以省略它。
更新自定义导航器
🌐 Update custom navigators
对于新的自定义集成,在应用中使用 createStandardRouterNavigator,或者在可重复使用的库中使用 integrateWithRouter。这些 API 使用 standard-navigation 协议来保持导航状态、描述符、动作和事件与 Expo Router 一致。
🌐 For new custom integrations, use createStandardRouterNavigator in an app or integrateWithRouter in a reusable library. These APIs use the standard-navigation contract to keep navigator state, descriptors, actions, and events aligned with Expo Router.
withLayoutContext 仍然支持现有的 React Navigation 导航器。如果你的集成使用了它,移除以前的第三个 useOnlyUserDefinedScreens 参数。文件系统路由仍然会被注册。当导航器 UI 需要区分布局声明的路由和文件系统路由时,请使用描述符 routeSource。
这个例子假设 TabNavigatorContent 已经从 React Navigation 的导航器工厂转换为一个可以接受 NavigatorContentProps 的组件。库的作者应该改为使用 standard-navigation 中的 createStandardNavigator 创建一个与框架无关的导航器,然后把这个导航器传给 integrateWithRouter。
🌐 The example assumes TabNavigatorContent has been converted from a React Navigation navigator factory to a component that accepts NavigatorContentProps. Library authors should instead create a framework-independent navigator with createStandardNavigator from standard-navigation, then pass that navigator to integrateWithRouter.
createStackNavigator 导出已从 expo-router/js-stack 中移除。这不会影响 createNativeStackNavigator 从 expo-router/native-stack 获取,它仍然可以使用。对于新的堆栈集成,建议使用带有 createStandardRouterNavigator 的标准导航器,或者将其传递给 integrateWithRouter 并使用匹配的 props 辅助方法:
🌐 The createStackNavigator export is removed from expo-router/js-stack. This does not affect createNativeStackNavigator from expo-router/native-stack, which remains available. For new stack integrations, prefer a standard navigator with createStandardRouterNavigator, or pass it to integrateWithRouter with the matching props helper:
从 expo-router 导入基础和原生堆栈辅助工具。从对应的 expo-router/js-stack、expo-router/js-tabs、expo-router/js-top-tabs 或 expo-router/native-tabs 入口点导入导航器特定的辅助工具。
🌐 Import the base and native stack helpers from expo-router. Import the navigator-specific helpers from the corresponding expo-router/js-stack, expo-router/js-tabs, expo-router/js-top-tabs, or expo-router/native-tabs entry point.
descriptor.route 上的 key 对于尚未有活动状态路由的已声明路由可以是 undefined。更新自定义导航器代码以处理这种情况。
🌐 The key on descriptor.route can be undefined for a declared route that does not yet have a live state route. Update custom navigator code to handle that case.
查看 自定义导航器 了解标准导航器概念。
🌐 See Custom navigators for standard navigator concepts.
已移除 expo-router/react-navigation 导出
🌐 Review removed expo-router/react-navigation exports
在 SDK 58 中,以下兼容性 API 已被移除或修改。仍然支持的导入可通过 expo-router/react-navigation 入口点 查看。
🌐 The following compatibility APIs are removed or changed in SDK 58. Imports that remain supported are listed by the expo-router/react-navigation entry point.