React Navigation 集成

编辑页面

通过启用 EAS Observe 的 React Navigation 集成,跟踪每个屏幕的渲染和交互耗时。


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

EAS Observe 提供了一个可选的 React Navigation 集成,用于收集按屏幕划分的指标,并使用该屏幕的路由名路径进行标记(例如,/Tabs/Sessions)。这样你就可以在仪表板中按屏幕比较导航性能,而不只是查看全应用范围的汇总数据。

如果你的应用使用的是 Expo Router,请改用 Expo Router 集成。本页面适用于直接使用 React Navigation 的应用。

前提条件

Prerequisites

3 requirements

1.

Expo SDK 56 及更高版本

React Navigation 集成在 SDK 56 及更高版本中可用。在更早的 SDK 中, expo-observe 仍会跟踪应用整体指标,但不会发出按屏幕划分的导航事件。

2.

一个已经在使用 EAS Observe 的应用

按照 开始使用 安装 expo-observe 并创建你的第一个 构建。

3.

应用中已安装 @react-navigation/native 7 或更高版本

该集成在运行时依赖 @react-navigation/native(v7.0.0 或更高版本)。如果 未安装该包,集成将静默无操作。

1

启用集成

必须在挂载前启用该集成,并且不能在运行时切换。应用挂载后调用 configure(),或在会话中途切换该标志,都会抛出错误。

在模块作用域内、任何屏幕挂载之前,使用 react-navigation 集成标志调用 Observe.configure()

App.tsx
import { Observe } from 'expo-observe'; Observe.configure({ integrations: { 'react-navigation': true }, });

2

将集成连接到你的导航

如何连接该集成取决于你的应用使用的是 React Navigation 的动态或静态配置。这两种方式都会记录相同的按屏幕指标。

对于动态配置,请将顶层的 <NavigationContainer> 替换为 <ObserveNavigationContainer>。它会包装原生容器,接受相同的 props,并转发相同的 ref。它还会订阅导航状态变化,从而记录按屏幕划分的渲染耗时。

App.tsx
import { Observe } from 'expo-observe'; import { ObserveNavigationContainer } from 'expo-observe/integrations/react-navigation'; Observe.configure({ integrations: { 'react-navigation': true }, }); export default function App() { return <ObserveNavigationContainer>{/* your navigators */}</ObserveNavigationContainer>; }

使用静态配置时,不需要替换 NavigationContainercreateStaticNavigation() 会替你渲染它。相反,你需要自己创建导航 ref,将其传给返回的 <Navigation> 元素,并使用同一个 ref 将该元素包裹在 <ObserveNavigationProvider> 中。该 provider 通过 ref 监听导航事件,并记录相同的按屏幕渲染耗时。

App.tsx
import { createStaticNavigation, useNavigationContainerRef } from '@react-navigation/native'; import { Observe } from 'expo-observe'; import { ObserveNavigationProvider } from 'expo-observe/integrations/react-navigation'; import { RootStack } from './navigation'; Observe.configure({ integrations: { 'react-navigation': true }, }); const Navigation = createStaticNavigation(RootStack); export default function App() { const navigationRef = useNavigationContainerRef(); return ( <ObserveNavigationProvider navigationRef={navigationRef}> <Navigation ref={navigationRef} /> </ObserveNavigationProvider> ); }
ObserveNavigationProvider 本身不会渲染容器。它会监听你传入的 navigationRef。它必须位于每个屏幕的祖先位置,这样 useObserve() 才能在这些屏幕中正常工作。

3

在屏幕中调用 useObserve()

使用 useObserve() hook 获取一个会自动限定到当前屏幕的 markInteractive。发出的事件会带上该屏幕的路径标签。

screens/Home.tsx
import { useObserve } from 'expo-observe'; import { useEffect } from 'react'; export default function Home() { const { markInteractive } = useObserve(); useEffect(() => { markInteractive(); }, [markInteractive]); return (/* your screen content */); }
如果集成被禁用,或者未安装 @react-navigation/nativeuseObserve() 会回退到全局的 AppMetrics.markInteractive。无论集成状态如何,你都可以保留这个 hook。

指标

按屏幕首次渲染(cold_ttr

它衡量的内容: 从导航动作被派发时开始计算(例如 navigation.navigate()),到目标屏幕首次获得焦点为止的时间。对于应用启动后的第一次获得焦点,该测量从 JS bundle 加载时开始,且事件会包含 isAppLaunch: true

在单个会话中,每个屏幕实例最多发出一次。

事件参数:

ParamTypeDescription
routeNamestring路由名路径(例如,/Tabs/Sessions)。
routeParamsobject当前聚焦的路由参数(例如,{ sessionId: 'abc' })。
isAppLaunchboolean当以进程启动时长为基准测量时为 true,后续导航则为 false

按屏幕热渲染(warm_ttr

它衡量的内容:cold_ttr 相同,但适用于在获得焦点之前就已经渲染过的屏幕,通常是因为它们已被预加载,或者用户返回到了这些屏幕。选项卡导航器中的兄弟屏幕只有在挂载之后才算作热渲染。使用 React Navigation v7 的默认 lazy: true 时,未聚焦的选项卡会保持未挂载状态,它们的首次聚焦会被记录为 cold_ttr

事件参数:

ParamTypeDescription
routeNamestring路由名路径(例如,/Tabs/Sessions)。
routeParamsobject当前聚焦的路由参数(例如,{ sessionId: 'abc' })。

按屏幕交互就绪时间(tti

它衡量的内容: 从导航动作被派发时开始计算,到目标屏幕调用 markInteractive() 为止的时间。每次导航只记录第一次调用,因此可以安全地多次调用 markInteractive()

事件参数:

ParamTypeDescription
routeNamestring路由名路径(例如,/Tabs/Sessions)。
routeParamsobject当前聚焦的路由参数。
...any通过 markInteractive({ ... }) 传入的任何自定义参数。

注意事项和故障排查

  • routeName 是根据路由名构建的(/Tabs/Sessions),因此路由参数永远不会出现在路径中。这使得指标在不同参数值之间保持稳定,仪表板会将它们归为同一类。参数值仍可通过 routeParams 在事件中获取。
  • 该集成仅在运行时安装了 @react-navigation/native 时才会激活。如果未安装该包,useObserve() 仍然可用,但不会发出按屏幕划分的导航指标。在未安装 @react-navigation/native 的情况下渲染 <ObserveNavigationContainer><ObserveNavigationProvider> 会抛出错误。
  • 必须在挂载前通过 Observe.configure({ integrations: { 'react-navigation': true } }) 启用该集成。在应用挂载后,或在 <ObserveNavigationContainer> / <ObserveNavigationProvider> 已经挂载后再切换它,都会抛出错误。
  • 使用静态配置时,请将同一个 ref 同时传给 <ObserveNavigationProvider><Navigation> 元素。如果 provider 接收到的 ref 并未连接到导航容器,则不会发出按屏幕指标。
  • markInteractive() 只有在屏幕获得焦点后才会记录。在未聚焦的屏幕上调用会更新内部状态,但在该屏幕获得焦点之前不会发出 tti 事件。
  • 请在屏幕组件内部调用 useObserve(),不要放在更高层的包装组件中。如果屏幕的身份在渲染之间发生变化,hook 会记录警告。如果 markInteractive() 记录了 Calling markInteractive on unmounted screenNo metadata available for the current screen,说明该调用发生在屏幕组件之外或在卸载之后。请将调用移动到屏幕组件内的 useEffect 中。
  • 关于 EAS Observe 的常规问题,请参阅 故障排查