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

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


navigate

如果页面不存在

创建

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 路由管理在日常开发和中高级前端面试中的核心知识点。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐