This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
React Navigation 集成
通过启用 EAS Observe 的 React Navigation 集成来跟踪每个屏幕的渲染和交互时间。
EAS Observe 是一个用于 React Navigation 的可选择集成,它会收集每个屏幕的指标,并用屏幕的路由名称路径(例如 /Tabs/Sessions)进行标记。这使你可以在仪表板中按屏幕比较导航性能,而不仅仅查看应用范围的汇总数据。
🌐 EAS Observe ships an opt-in integration for React Navigation that collects per-screen metrics tagged with the screen's route-name path (for example, /Tabs/Sessions). This lets you compare navigation performance by screen in the dashboard instead of looking only at app-wide aggregates.
如果你的应用使用 Expo Router,请改用 Expo Router 集成。此页面适用于直接使用 React Navigation 的应用。
🌐 If your app uses Expo Router, use the Expo Router integration instead. This page is for apps that use React Navigation directly.
先决条件
🌐 Prerequisites
3 要求
3 要求
1.
React Navigation 集成适用于 SDK 56 及更高版本。在较早的 SDK 中,expo-observe 仍会跟踪全应用的指标,但不会发出每个屏幕的导航事件。
2.
按照 入门指南 安装 expo-observe 并创建你的第一个构建。
3.
该集成在运行时依赖 @react-navigation/native(v7.0.0 或更高版本)。如果未安装该包,集成将静默不做任何操作。
1
启用集成
🌐 Enable the integration
警告 集成必须在挂载前启用,且不能在运行时切换。在应用挂载后调用
configure(),或在会话中途切换标志,会抛出错误。
在任何屏幕挂载之前,在模块作用域内使用 react-navigation 集成标志调用 Observe.configure():
🌐 Call Observe.configure() with the react-navigation integration flag at module scope, before any screen mounts:
import { Observe } from 'expo-observe'; Observe.configure({ integrations: { 'react-navigation': true }, });
2
将集成连接到你的导航
🌐 Connect the integration to your navigation
你如何连接集成取决于你的应用是否使用 React Navigation 的动态或静态配置。这两种方法都会记录相同的每个屏幕的指标。
🌐 How you connect the integration depends on whether your app uses React Navigation's dynamic or static configuration. Both approaches record the same per-screen metrics.
对于动态配置,将你的顶层 <NavigationContainer> 替换为 <ObserveNavigationContainer>。它封装了原生容器,接受相同的属性,并转发相同的引用。它还会订阅导航状态变化,因此可以记录每个屏幕的渲染时间。
🌐 For dynamic configuration, replace your top-level <NavigationContainer> with <ObserveNavigationContainer>. It wraps the stock container, accepts the same props, and forwards the same ref. It also subscribes to navigation state changes so it can record per-screen render timings.
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>; }
使用 静态配置 时,没有 NavigationContainer 可以替换。createStaticNavigation() 会为你渲染一个。相反,你需要自己创建导航引用,将其传递给返回的 <Navigation> 元素,并使用相同的引用将该元素封装在 <ObserveNavigationProvider> 中。Provider 通过引用监听导航事件,并记录每个屏幕渲染的相同时间。
🌐 With static configuration, there is no NavigationContainer to replace. createStaticNavigation() renders one for you. Instead, create the navigation ref yourself, pass it to the returned <Navigation> element, and wrap the element in <ObserveNavigationProvider> with the same ref. The provider listens to navigation events through the ref and records the same per-screen render timings.
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()
🌐 Call useObserve() in your screens
使用 useObserve() 钩子获取一个自动作用于当前屏幕的 markInteractive。发出的事件会附上屏幕的路径标签。
🌐 Use the useObserve() hook to get a markInteractive that is automatically scoped to the current screen. The emitted event is tagged with the screen's path.
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/native,useObserve()将回退到全局AppMetrics.markInteractive。无论集成状态如何,你都可以保留该钩子。
指标
🌐 Metrics
每屏首次渲染(cold_ttr)
🌐 Per-screen first render (cold_ttr)
它衡量的内容: 从导航操作被触发(例如,navigation.navigate())到目标屏幕首次获得焦点的时间。对于应用启动后的首次焦点,测量时间从 JS 包加载时开始,事件中包含 isAppLaunch: true。
在一次会话中的每个屏幕实例最多发出一次。
🌐 Emitted at most once per screen instance within a session.
事件参数:
| 参数 | 类型 | 描述 |
|---|---|---|
routeName | string | 路由名称路径(例如,/Tabs/Sessions)。 |
routeParams | object | 关注的路由参数(例如,{ sessionId: 'abc' })。 |
isAppLaunch | boolean | 相对于进程启动时测量的 true,后续导航的 false。 |
每屏幕预热渲染(warm_ttr)
🌐 Per-screen warm render (warm_ttr)
测量内容: 与 cold_ttr 相同,但针对那些在获取焦点前已经渲染的屏幕,通常是因为它们被预加载或用户返回到这些屏幕。仅当 Tab 导航器的同级页面被挂载后,它们才计为热屏。使用 React Navigation v7 默认的 lazy: true 时,未聚焦的标签页保持未挂载状态,其第一次获取焦点会记录为 cold_ttr。
事件参数:
| 参数 | 类型 | 描述 |
|---|---|---|
routeName | string | 路由名称路径(例如,/Tabs/Sessions)。 |
routeParams | object | 聚焦的路由参数(例如,{ sessionId: 'abc' })。 |
每屏到交互时间(tti)
🌐 Per-screen time to interactive (tti)
它测量的内容: 从导航操作被分发到目标屏幕上调用 markInteractive() 的时间。每次导航只记录第一次调用,因此可以安全地多次调用 markInteractive()。
事件参数:
| 参数 | 类型 | 描述 |
|---|---|---|
routeName | string | 路由名称路径(例如,/Tabs/Sessions)。 |
routeParams | object | 关注的路由参数。 |
... | any | 通过 markInteractive({ ... }) 传递的任何自定义参数。 |
注意事项与故障排除
🌐 Notes and troubleshooting
routeName是由路由名称(/Tabs/Sessions)构建的,因此路由参数从不出现在路径中。这可以使指标在不同的参数值下保持稳定,从而仪表板会将它们归类在一起。参数值仍然可以通过routeParams在事件中获得。- 该集成仅在运行时安装了
@react-navigation/native时才会激活。如果未安装,useObserve()仍然可以正常工作,但不会发出每屏导航指标。在没有@react-navigation/native的情况下渲染<ObserveNavigationContainer>或<ObserveNavigationProvider>会抛出错误。 - 在通过
Observe.configure({ integrations: { 'react-navigation': true } })挂载之前必须启用该集成。在应用挂载之后,或在<ObserveNavigationContainer>或<ObserveNavigationProvider>挂载之后切换它,会抛出错误。 - 在静态配置下,将相同的 ref 传递给
<ObserveNavigationProvider>和<Navigation>元素。如果提供者收到的 ref 未连接到导航容器,则不会发出每个屏幕的指标。 markInteractive()仅在屏幕获得焦点时记录一次。在未获得焦点的屏幕上进行的调用会更新内部状态,但在屏幕获得焦点之前不会触发tti事件。- 在屏幕组件内部调用
useObserve(),而不是在更高级别的封装器中。如果屏幕的身份在渲染之间发生变化,该钩子会记录一个警告。如果markInteractive()记录了Calling markInteractive on unmounted screen或No metadata available for the current screen,说明调用发生在屏幕组件外部或卸载之后。将调用移到屏幕组件内部的useEffect中。 - 有关 EAS Observe 的一般问题,请参阅 故障排除。