6.1 页面导航:React Navigation 与 Navigator


6.1 页面导航:React Navigation 与 Navigator

本节摘要:页面导航决定用户如何在界面之间切换。RN 用社区库 React Navigation,支持栈式、标签、抽屉三种导航器;Flutter 用内置 Navigator 与路由机制。本节讲清两种导航形态(栈式与标签式)的心智模型、双框架的导航实现与页面传参方法,并对比两者的配置差异。核心心智:栈式管深度、标签管宽度。

先说结论

阅读完本节,你应当能够:

  1. 说清栈式导航与标签导航的区别与适用场景。
  2. 用 React Navigation 搭建栈式与标签导航。
  3. 用 Flutter Navigator 实现页面跳转与传参。
  4. 理解"导航状态"也是一种应用状态(第 5 章主题的延伸)。

一、问题与直觉

一个单页面的应用几乎不存在——真实应用都有"列表点进去看详情、底部切换模块"这类多页面结构。导航要解决的,就是"页面之间怎么跳、怎么返回、参数怎么带"。

先建立两种导航形态的心智模型,它们覆盖了绝大多数 App 的导航需求:

栈式导航像一摞盘子。进入新页面 = 往上放一个盘子,返回 = 拿走顶上的盘子。适合"A 列表 → B 详情 → C 编辑"这类线性流程。iOS 的 push 返回手势、Android 的系统返回键,都对应栈的弹出操作。

标签导航像文件柜的多个抽屉。每个抽屉是一个独立模块,点标签切换,互不堆叠。适合"首页、消息、我的"这类平级模块。

一句话点题:栈式管"深度",标签管"宽度"。深度用栈(逐层深入),宽度用标签(平级切换)。

二、核心原理

2.1 RN 侧:React Navigation

React Navigation 是 RN 社区最流行的导航库。核心概念有三:Navigator 管理一组屏幕,Screen 代表一个页面,每个屏幕组件拿到 navigation prop 执行跳转。

栈式导航

import { createNativeStackNavigator } from '@react-navigation/native-stack'; const Stack = createNativeStackNavigator(); function AppNavigator() { return ( <Stack.Navigator> <Stack.Screen name="Home" component={HomeScreen} /> <Stack.Screen name="Details" component={DetailsScreen} /> </Stack.Navigator> ); }

标签导航

import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; const Tab = createBottomTabNavigator(); function MainTabs() { return ( <Tab.Navigator> <Tab.Screen name="Home" component={HomeScreen} /> <Tab.Screen name="Settings" component={SettingsScreen} /> </Tab.Navigator> ); }

跳转操作

navigation.navigate('Details', { id: 42 }); // 跳转并传参 navigation.push('Details', { id: 43 }); // 压入新实例 navigation.goBack(); // 返回

navigate 与 push 的区别值得记住:navigate 如果目标已在栈中会复用它,push 总是创建新实例。需要"重复进入同一页面"时用 push。

2.1.1 抽屉导航:第三种形态

栈式与标签之外,抽屉导航是第三种常见形态。它从屏幕边缘滑出侧边菜单,适合"导航项多、不想占屏幕空间"的应用。RN 用 createDrawerNavigator,Flutter 用 Scaffold 的 drawer 属性。抽屉通常用于设置、关于、退出登录这类低频但重要的入口。三种导航形态可以组合使用:标签导航管理模块,模块内部用栈式导航管页面深度,需要时再用抽屉收纳次要入口。

2.1.2 导航架构图

把三种形态与它们的组合关系画成一张图,导航体系的骨架就一目了然:

2.1.2 导航架构图

这张图是导航设计的速查卡:三种形态各司其职,组合使用构成完整导航体系。

2.2 Flutter 侧:Navigator 与路由

Flutter 的 Navigator 是框架内置能力,开箱即用。基础跳转:

Navigator.push( context, MaterialPageRoute(builder: (context) => const DetailsScreen()), );

返回用 Navigator.pop(context)。命名路由适合管理较多页面的应用:

MaterialApp( initialRoute: '/', routes: { '/': (context) => const HomeScreen(), '/details': (context) => const DetailsScreen(), }, );

跳转传参通过构造函数传入:

Navigator.push( context, MaterialPageRoute( builder: (context) => DetailsScreen(id: 42), ), );

2.2.1 页面回传结果:双框架的常见需求

真实场景里经常需要"B 页操作完,回传结果给 A 页"。双框架的解法对应着各自的状态流动方式。

RN 的做法是传回调:A 页 navigate 时给 B 页一个参数函数,B 页完成后调用它:

navigation.navigate('Edit', { onSave: (text) => updateTodo(text), });

Flutter 的做法是 await 返回值:push 返回一个 Future,pop 时把结果传回去:

final result = await Navigator.push( context, MaterialPageRoute(builder: (context) => const EditScreen()), ); // result 就是 B 页 pop 回来的值

两种方式对应着两个框架的异步心智:RN 的回调式、Flutter 的 Future 式。理解"回传"这个需求,比记 API 更有价值——它在导航、状态、异步三个主题的交汇处,是真正的综合题。

2.3 导航状态与应用的结合

导航状态本身也是一种应用状态。RN 的 navigation prop、Flutter 的 Navigator 都维护着"当前页面栈"这个隐式状态。它与第 5 章的状态管理结合最典型的是:页面间传参——A 页跳 B 页带参数,B 页回传结果给 A 页。这本质是"状态跨页面流动",用好了,页面间协作才顺畅。

三、工程实践要点

3.1 双框架导航对照

维度 React Native Flutter
方案来源 社区库 React Navigation 框架内置 Navigator
安装配置 需安装依赖并包裹容器 开箱即用
栈式导航 createNativeStackNavigator Navigator.push
标签导航 createBottomTabNavigator BottomNavigationBar
页面传参 navigate 第二参数 构造函数传入
返回操作 navigation.goBack Navigator.pop

3.2 导航高频坑

坑一:忘记包裹 NavigationContainer。RN 的导航器必须包在容器里,否则报错。

坑二:导航到不存在的路由。Flutter 命名路由跳转时路由名拼错,运行时报错。保持路由名集中管理可减少此类错误。

坑三:在页面组件外拿 navigation。RN 的 navigation prop 只在屏幕组件里直接可用,组件树深处的子组件要用 useNavigation Hook。

⚠️ 常见坑(RN):navigate 与 push 混用导致页面栈混乱。理解差异:需要"返回时回到之前页面"用 navigate,需要"反复进入同一页面"用 push。栈的行为决定了返回体验。
⚠️ 常见坑(Flutter):在异步回调里用 mounted 检查后再 Navigator.pop。页面可能已弹出,再 pop 会报错。回调前先判断当前 State 是否还在树上。
💡 关键直觉:导航设计要站在用户角度想"返回会去哪"。栈式导航里每个跳转都决定了一次返回行为,设计时先画一遍"页面栈的进进出出",比直接写代码稳得多。

3.3 动手验证:给待办应用加导航

给待办应用加两个页面:列表页(待办列表)与详情页(点击待办查看详情)。用栈式导航实现跳转与传参,再在底部加一个"设置"标签页。这个练习把本节所有概念串起来:栈式、标签式、传参、返回。做完后你的待办应用就有了"多页面"的骨架,为 6.2 节联网后的完整应用打底。

FAQ:页面导航的常见疑问

问:深链接(Deep Link)是什么?要不要学? 深链接是"从应用外部打开指定页面"的机制——比如收到推送点一下直接进到商品详情页。它涉及导航与系统层面的配合,是进阶话题。先掌握栈式与标签式导航,深链接等到真有"外部唤醒"需求时再学,不必一开始就啃。

问:页面多了,导航文件怎么组织才不乱? 把导航器独立成文件管理。RN 用根导航器文件统一注册所有 Screen;Flutter 把路由表集中在 MaterialApp 的配置里。经验法则:新页面必须在导航配置里注册,注册表就是应用的"页面地图"。维护好这张地图,页面再多也不乱。

问:Android 返回键和 iOS 返回手势行为一致吗? 不完全一致,但导航库会尽量统一。RN 的 React Navigation 与 Flutter 的 Navigator 都处理了系统返回的适配。需要平台差异时(比如 Android 双击返回退出应用),用 Platform 判断写少量平台代码即可。多数场景下,导航库已经把差异抹平了。

问:页面跳转时怎么传复杂对象? 传引用即可,但要注意序列化边界。RN 与 Flutter 在页面跳转时通常传递对象引用(同进程内),可以直接传对象;只有涉及持久化或跨进程(深链接)时才需要序列化成可传输的格式。简单场景传 id 等标量最稳妥,需要详情数据时用 id 再查一次,反而更清晰。

3.4 导航与状态管理的一个交汇点

导航与第 5 章的状态管理有一个重要的交汇点:导航参数与会话状态。页面跳转时传的参数(比如商品 id)属于"临时导航数据",适合随导航传递;而用户登录信息这类"贯穿全程的数据"属于全局状态,应该放在状态库里。分清这两类,就不会出现"把用户信息当导航参数到处传"的糟糕设计。判断标准:数据只被当前跳转流程使用,放导航参数;被多个无关页面长期使用,放全局状态。这个分界在真实项目里反复出现,值得现在就建立。

3.5 导航相关的常见陷阱补充

导航还有几个细节值得提前知道。第一,页面状态在返回时会保留吗?RN 与 Flutter 的栈式导航默认保留页面实例,返回时状态还在;但标签导航切换模块时,未激活的页面可能被重建或保留,行为因配置而异。第二,导航参数的更新——同一个页面被带不同参数再次进入时,RN 用 useEffect 监听参数变化、Flutter 用 didUpdateWidget,都用于"参数变了要刷新内容"。第三,深层页面直接返回——用户可能从最深层连续返回多次,导航库都有对应的 popToTop 或返回根路由的方法。这些细节不会在第一个导航 Demo 里遇到,但多页面应用做深了就绕不开。

3.6 导航架构的分层思考

多页面应用的导航架构值得提前分层设计,而不是边写边加。通常分三层:根导航器(决定整个 App 的导航骨架,标签导航还是栈导航)、模块导航(每个模块内部的页面栈)、业务页面(具体的 Screen)。用导航库时,这三层各有对应的组织方式——RN 用嵌套导航器实现,Flutter 用嵌套 Navigator 或路由分组。分层的好处是:新增页面时知道该放进哪层,模块之间互不干扰。入门项目也许只有一层,但一开始就按分层的思路组织,后面扩展会顺畅得多。

3.7 本节的一个自查清单

导航学完,用一组问题自查:能说清栈式与标签式各自的适用场景吗?能在 RN 与 Flutter 里各写出一个跳转并传参的最小例子吗?知道 navigate 与 push 的区别吗?能说清"导航参数与全局状态"的分界吗?前两个问题检验"会用",后两个检验"懂原理"。四个都能答上,导航这一节就真正过关了。如果还有含糊,回到对应小节再读一遍——导航是"多页面应用"的骨架,这块不牢,后面的功能都是散件。

补充一句关于导航与用户体验的联系:导航不只是技术实现,它直接塑造用户体验。栈式导航让用户知道"我可以返回",标签导航让用户知道"我在哪个模块",良好的导航设计让用户始终清楚自己身处何地、能去哪里。写导航代码时多站在用户视角思考"下一步想去哪、怎么回来",导航体验就会自然变好。这也是为什么导航常被看作"应用的信息架构"——它决定了用户如何理解和使用你的应用。

核心回顾

  • 两种形态:栈式管深度(逐层深入),标签管宽度(平级切换)。
  • 三种形态组合:标签管模块、栈管深度、抽屉收尾,组合成完整体系。
  • RN 方案:React Navigation 社区库,Navigator 加 Screen 结构。
  • Flutter 方案:Navigator 内置能力,push 与 pop 基础操作。
  • 跳转操作:navigate 复用栈中页面,push 新建实例,goBack 返回。
  • 传参方式:RN 用 navigate 第二参数,Flutter 用构造函数。
  • 回传结果:RN 传回调,Flutter await push 返回值。
  • 导航状态:导航栈是隐式应用状态,跨页面传参本质是状态流动。
  • 配置差异:RN 需装库包容器,Flutter 开箱即用。

页面能跳了,下一步让页面有内容——网络请求,从 API 拉真实数据进来。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U