RN 路由栈管理、页面销毁、返回拦截

React Native 的路由栈管理、页面销毁、返回拦截 ,如果现在是 React Native 新项目,基本都是围绕 React Navigation 7.x(6.x 思路也一样) 来讲。

下面按面试和实际开发两个角度总结。


一、RN 路由栈(Navigation Stack)

React Navigation 的 Stack Navigator,本质就是一个页面栈。

复制代码
Home

push Detail

复制代码
Home
 ↓
Detail

再 push Order

复制代码
Home
 ↓
Detail
 ↓
Order

返回(goBack)

复制代码
Home
 ↓
Detail

常见API

push

每次都会创建新页面

复制代码
navigation.push("Detail");
navigation.push("Detail");

栈

复制代码
Home
Detail
Detail

即使页面一样,也会创建。


如果页面不存在

创建

复制代码
Home
↓

Detail

如果已经存在

直接跳过去

不会重复创建

复制代码
navigation.navigate("Detail");

所以:

复制代码
push

一定新增页面。

复制代码
navigate

优先复用。


replace

替换当前页面

复制代码
Home
↓

Login

replace

复制代码
Home
↓

Main

Login 被销毁。

复制代码
navigation.replace("Main");

常用于

登录成功

Splash

欢迎页


pop

返回N层

复制代码
navigation.pop(2);

Home
↓

A
↓

B
↓

C

pop(2)

复制代码
Home
↓

A

popToTop

直接回首页

复制代码
navigation.popToTop();

reset

重建整个导航栈

例如退出登录

复制代码
navigation.reset({
  index: 0,
  routes: [{ name: "Login" }],
});

变成

复制代码
Login

之前所有页面全部销毁。


二、页面生命周期

React Native 页面不是 Vue。

React Navigation 提供了一套 Navigation 生命周期。

主要:

复制代码
mount

focus

blur

unmount

mount

第一次创建

复制代码
useEffect(() => {
    console.log("mount");

    return () => {
        console.log("unmount");
    };
}, []);

focus

页面进入前台

复制代码
import { useFocusEffect } from "@react-navigation/native";

useFocusEffect(
  React.useCallback(() => {
    console.log("focus");

    return () => {
      console.log("blur");
    };
  }, [])
);

什么时候触发?

复制代码
Home
↓

Detail

进入 Detail

复制代码
Home blur

Detail focus

返回

复制代码
Detail blur

Home focus

useIsFocused

判断当前是否显示

复制代码
const isFocused = useIsFocused();

useEffect(() => {
    if (isFocused) {
        loadData();
    }
}, [isFocused]);

很多列表都会这样刷新。


三、页面销毁(Unmount)

很多人误解:

返回才销毁。

实际上:

只有真正移除 Stack 才销毁。

例如:

复制代码
Home
↓

Detail

goBack

Detail

unmount

Home

不会重新 mount。


push

复制代码
Home
↓

Detail
↓

Order

Order

mount

Detail

没有销毁

只是 blur。


所以:

复制代码
Home

其实一直活着。


如何强制销毁页面?

replace

复制代码
replace()

替换页面。


reset

重建导航。


条件渲染

有时直接不渲染 Stack。

例如:

复制代码
{
    isLogin
        ? <MainStack />
        : <LoginStack />
}

切换时整个 Stack 全部销毁。


四、返回拦截

最常见:

编辑页面

退出提醒


beforeRemove

官方推荐

复制代码
useEffect(() => {
  const unsubscribe = navigation.addListener(
    "beforeRemove",
    (e) => {

      e.preventDefault();

      Alert.alert(
        "提示",
        "确定退出?",
        [
          {
            text: "取消",
            style: "cancel",
          },
          {
            text: "确定",
            onPress: () => navigation.dispatch(e.data.action),
          },
        ]
      );
    }
  );

  return unsubscribe;
}, [navigation]);

所有返回都会拦截:

  • Header 返回

  • 手势返回

  • goBack()

  • Android 返回键


Android BackHandler

安卓物理返回键

复制代码
import { BackHandler } from "react-native";

useEffect(() => {

    const backAction = () => {

        Alert.alert("退出?");

        return true;

    };

    const sub = BackHandler.addEventListener(
        "hardwareBackPress",
        backAction
    );

    return () => sub.remove();

}, []);

返回

复制代码
true

表示

我处理了

系统不要返回。

返回

复制代码
false

系统继续默认返回。


五、监听页面事件

除了 focus,还有:

复制代码
navigation.addListener("focus", () => {})

navigation.addListener("blur", () => {})

navigation.addListener("state", () => {})

navigation.addListener("beforeRemove", () => {})

例如:

复制代码
useEffect(() => {

   const sub = navigation.addListener("focus", () => {
      console.log("页面显示");
   });

   return sub;

}, []);

六、页面缓存机制

React Navigation 默认:

不会因为切换到其他页面就销毁当前页面。

例如:

复制代码
Home
↓

Detail
↓

Order

内存中实际上:

复制代码
Home

Detail

Order

只有:

复制代码
pop

replace

reset

才真正销毁。


Tab Navigator 也是类似。

复制代码
Home

Mine

Setting

切换:

复制代码
Home
↓

Mine

Home 不会重新创建。

所以很多人会发现:

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

只执行一次。

真正刷新应该使用

复制代码
useFocusEffect()

七、实际项目中的最佳实践

场景 推荐方案 原因
页面首次加载数据 useEffect(() => {}, []) 只在首次挂载执行
每次返回页面刷新数据 useFocusEffect 或 useIsFocused 页面重新获得焦点时执行
登录成功进入首页 replace 或 reset 防止返回登录页
退出登录 reset 清空整个导航栈
编辑页面防止误返回 beforeRemove 可统一拦截所有返回方式
Android 物理返回键 BackHandler(必要时配合 beforeRemove) 处理退出应用或自定义返回逻辑
返回上一页 goBack() 标准返回操作
连续打开同一页面 push() 每次创建新的页面实例
避免重复打开已有页面 navigate() 优先复用已有页面

面试高频问题

  1. push 和 navigate 有什么区别?

    • push:始终创建新的页面实例。

    • navigate:若目标页面已存在(根据导航器行为),优先跳转到已有页面,避免重复创建。

  2. 页面切换时为什么 useEffect(() => {}, []) 不会再次执行?

    • 因为页面通常没有被销毁,只是从 focus 变为 blur。再次显示时不会重新 mount,因此应使用 useFocusEffect 或监听 focus 事件处理每次进入页面的逻辑。
  3. 如何清空整个导航栈?

    • 使用 navigation.reset(),重新设置导航状态。
  4. 如何拦截返回操作?

    • 推荐使用 beforeRemove 统一拦截导航返回;若需要处理 Android 物理返回键,可结合 BackHandler 使用。

掌握这些内容,基本覆盖了 React Native 路由管理在日常开发和中高级前端面试中的核心知识点。

相关推荐
衍辉channel3 小时前
衍辉AI速递 10.14|谷歌发布Gemini 4 Argon模型等9条AI资讯
javascript
vipxieliang3 小时前
JavaScript 事件循环与任务队列:从 setTimeout 到 Promise
前端·javascript
Misnearch4 小时前
React中的回调
前端·javascript·react.js
Eider19986 小时前
大模型输出格式幻觉解决思路
开发语言·前端·javascript
志尊宝6 小时前
Vue3 零基础每日笔记(085):项目上线前 Checklist——环境变量、报错监控、安全自查
前端·javascript·笔记·安全·信息可视化·echarts
志尊宝6 小时前
Vue3 零基础每日笔记(088·完结):从零到一——一个完整 Vue3 项目的成长复盘
前端·javascript·vue.js·笔记·ecmascript·#vue.js
传人once6 小时前
企业官网静态页基础结构如何搭
javascript·css
桔筐6 小时前
Vue中DOM的data-*自定义属性(dataset)与Vue data响应式变量区别详解
前端·javascript·vue.js
damoluomu6 小时前
静态站点生成器怎么选:Node.js 生态里常用的五个(番外一)
javascript·css·typescript·node.js·html
vipxieliang7 小时前
JavaScript 执行上下文与调用栈:从原理到调试实战
前端·javascript