React Navigation 生命周期完整心智模型


网罗开发 (小红书、快手、视频号同名)

大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。

图书作者:《ESP32-C3 物联网工程开发实战》
图书作者:《SwiftUI 入门,进阶与实战》
超级个体:COC上海社区主理人
特约讲师:大学讲师,谷歌亚马逊分享嘉宾
科技博主:华为HDE/HDG

我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验 。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。

展菲:您的前沿技术领航员

👋 大家好,我是展菲!

📱 全网搜索"展菲",即可纵览我在各大平台的知识足迹。

📣 公众号"Swift社区",每周定时推送干货满满的技术长文,从新兴框架的剖析到运维实战的复盘,助您技术进阶之路畅通无阻。

💬 微信端添加好友"fzhanfei",与我直接交流,不管是项目瓶颈的求助,还是行业趋势的探讨,随时畅所欲言。

📅 最新动态:2025 年 3 月 17 日

快来加入技术社区,一起挖掘技术的无限潜能,携手迈向数字化新征程!

文章目录

摘要

在 React Navigation 里,生命周期问题几乎是所有复杂 Bug 的源头

很多看起来"很诡异"的现象,本质上都能归结为一句话:

你以为页面已经销毁了,但它其实还活着

你以为 useEffect 会重新跑,但它其实根本没机会

这篇文章不打算从 API 一个个列,而是从心智模型出发,帮你真正建立三件事的统一认知:

  • 组件生命周期(React)
  • 页面生命周期(Navigation)
  • 业务生命周期(用户视角)

当这三层对齐之后,你会发现:

  • 页面切换不再"玄学"
  • 副作用管理变得非常清晰
  • 很多历史遗留 Bug 一下子就能解释通了

先说一个非常真实的现象。

你可能:

  • 用过 useEffect
  • 用过 useFocusEffect
  • 也知道有 focusblur

但当遇到下面这些问题时,还是会懵:

  • 为什么返回页面后数据没刷新?
  • 为什么某个请求跑了两次?
  • 为什么定时器越跑越多?
  • 为什么 setState 报错组件已卸载,但我明明还能看到页面?

原因只有一个:
你脑子里只有"组件生命周期",没有"页面生命周期模型"。

先建立一个总览:三层生命周期同时存在

在 RN + React Navigation 中,你必须同时理解三套生命周期。

第一层:React 组件生命周期

这是大家最熟的:

  • mount
  • update
  • unmount
  • useEffect / cleanup

它只关心一件事:组件在不在内存里。

第二层:Navigation 页面生命周期

这是最容易被忽略的:

  • focus
  • blur
  • transition
  • stack 中的存在状态

它关心的是:页面是否处于"当前活跃状态"。

第三层:业务生命周期(用户视角)

这是最容易被写错的:

  • 用户是否正在看这个页面
  • 用户是否关心当前副作用
  • 当前逻辑是否"还有意义"

绝大多数副作用,其实属于这一层。

核心结论先给出

在进入细节之前,先给你三条"底层规则",后面所有内容都会围绕它展开。

  1. 页面 blur ≠ 组件 unmount
  2. useEffect 默认只和 mount / unmount 有关
  3. 绝大多数业务副作用,应该绑定 focus / blur,而不是 mount

如果你把这三条真正吃透,80% 的 Navigation Bug 都会消失。

从一个最常见的页面跳转说起

我们从最典型的 Stack Navigation 开始。

txt 复制代码
Home → Detail → Profile

实际发生了什么(默认配置)

当你从 Home 跳到 Detail:

  • Home:blur
  • Detail:mount + focus
  • Home:仍然 mounted

再从 Detail 跳到 Profile:

  • Detail:blur
  • Profile:mount + focus
  • Home、Detail:全部还在内存里

这一步,是很多人理解错误的起点。

时间轴拆解:一次完整的页面往返

我们用 Home → Detail → Home 举例。

第一次进入 Home

txt 复制代码
Home mount
Home focus
  • useEffect(() => {}, []) 执行
  • useFocusEffect 执行

从 Home 跳转到 Detail

txt 复制代码
Home blur
Detail mount
Detail focus

注意这一步:

  • Home 没有 unmount
  • Home 的 useEffect cleanup 不会执行

从 Detail 返回 Home

txt 复制代码
Detail blur
Home focus

这里是高频踩坑点:

  • Home 不会重新 mount
  • useEffect(() => {}, []) 不会再跑
  • 只有 focus 相关逻辑会触发

用一张"心智模型表"记住它

行为 useEffect([]) useFocusEffect 组件是否存在
首次进入页面 执行 执行
跳转到其他页面 不触发 cleanup
返回页面 不执行 再次执行
页面被真正销毁 cleanup cleanup

这张表,建议你直接刻进脑子里。

很多人会写这样的代码:

tsx 复制代码
useEffect(() => {
  fetchData();
}, []);

然后发现:

  • 页面第一次进来 OK
  • 返回页面后数据不刷新
  • 只能靠手动刷新兜底

问题不是 useEffect 有 bug,而是你把"页面激活"当成了"组件创建"。

在 Navigation 世界里:

页面重新可见 ≠ 组件重新创建

正确的心智转变:页面 = 有状态的长生命周期对象

你应该把一个 Screen 理解为:

一个长期存在的对象,在不同时间段被 focus / blur

而不是:

每次进入就 new 一个,用完就销毁

一旦你接受了这个模型,很多设计会自然发生变化。

什么时候该用 useEffect,什么时候该用 useFocusEffect

这是最实用的问题,没有之一。

适合 useEffect 的场景

这些逻辑只和组件存在有关

  • 初始化静态配置
  • 注册全局工具(一次即可)
  • 只需要执行一次的逻辑
tsx 复制代码
useEffect(() => {
  initAnalytics();
}, []);

必须用 useFocusEffect 的场景

这些逻辑和页面是否可见强相关

  • 页面级数据请求
  • 轮询 / 定时器
  • WebSocket 订阅
  • 页面埋点曝光
  • 动画启动 / 停止
tsx 复制代码
useFocusEffect(
  useCallback(() => {
    startPolling();
    return stopPolling;
  }, [])
);

一个完整的可运行示例:对比两种写法

错误示例:useEffect 管理页面请求

tsx 复制代码
useEffect(() => {
  console.log('fetch data');
  fetchData();
}, []);

表现:

  • 只在第一次进入时请求
  • 返回页面数据不更新

正确示例:useFocusEffect 管理页面请求

tsx 复制代码
useFocusEffect(
  useCallback(() => {
    console.log('fetch data on focus');
    fetchData();
  }, [])
);

表现:

  • 每次页面可见都会触发
  • 行为符合用户直觉

unmountOnBlur 是"银弹"吗?

很多人会问:
我直接把页面 blur 时 unmount 不就完了?

tsx 复制代码
options={{ unmountOnBlur: true }}

它能解决什么?

  • 副作用自动清理
  • useEffect 行为更"像直觉"

它带来的代价

  • 页面状态完全丢失
  • 重进页面性能开销变大
  • 动画 / 滚动位置无法保留

结论是:

它是工具,不是默认答案

大多数情况下,你需要的是:

  • 正确管理 focus 生命周期
  • 而不是强行销毁页面

一个判断标准:问自己三个问题

每次写副作用前,问自己:

  1. 页面不可见时,这个逻辑还有意义吗?
  2. 用户切走页面后,我是否还关心这个结果?
  3. 返回页面时,是否应该"重新激活"它?

如果答案偏向"是 / 否",你就知道该选哪种生命周期了。

总结

React Navigation 的生命周期并不复杂,复杂的是我们用错了抽象层级

你真正需要记住的只有一句话:

组件生命周期决定"在不在",页面生命周期决定"该不该跑"。

当你把:

  • useEffect → 组件存在
  • useFocusEffect → 页面可见

这条边界画清楚之后:

  • 页面逻辑会变得非常稳定
  • Bug 数量会明显下降
  • 项目越大,收益越明显
相关推荐
若梦plus2 小时前
从微信公众号&小程序的SDK剖析JSBridge
前端
用泥种荷花2 小时前
Python环境安装
前端
Light602 小时前
性能提升 60%:前端性能优化终极指南
前端·性能优化·图片压缩·渲染优化·按需拆包·边缘缓存·ai 自动化
Jimmy2 小时前
年终总结 - 2025 故事集
前端·后端·程序员
烛阴2 小时前
C# 正则表达式(2):Regex 基础语法与常用 API 全解析
前端·正则表达式·c#
roman_日积跬步-终至千里2 小时前
【人工智能导论】02-搜索-高级搜索策略探索篇:从约束满足到博弈搜索
java·前端·人工智能
GIS之路3 小时前
GIS 数据转换:使用 GDAL 将 TXT 转换为 Shp 数据
前端
多看书少吃饭3 小时前
从Vue到Nuxt.js
前端·javascript·vue.js
前端一小卒3 小时前
从 v5 到 v6:这次 Ant Design 升级真的香
前端·javascript