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

面试高频问题

  1. pushnavigate 有什么区别?

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

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

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

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

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

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

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

相关推荐
_lucas1 小时前
做了一个glsl在线调试工具
前端·javascript·three.js
To_OC9 小时前
LC 51 N 皇后:我以为难的是回溯,结果栽在了对角线下标
javascript·算法·leetcode
小林ixn11 小时前
从零到一理解 React 父子组件通信:手写一个 Todo 应用带你彻底搞懂单向数据流
前端·javascript·react.js
窝子面13 小时前
手搓最简前后端协作-node
javascript·数据库
qetfw13 小时前
MXU:Tauri 2 + React 的 MaaFramework 跨平台 GUI 源码
前端·python·react.js·前端框架·开源项目·效率工具
kyriewen14 小时前
我让AI给前端项目做了一次完整的Code Review——它和人类的差距,比我想的大得多
前端·javascript·ai编程
এ慕ོ冬℘゜14 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
鱼毓屿御15 小时前
从「只会聊」到「边想边做」的跃迁
前端·学习·react.js
sugar__salt16 小时前
Vue3 表单双向绑定与响应式核心 API 技术详解
前端·javascript·vue.js