You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于wix/react-native-navigation实现全局HOC管控网络状态页面切换

给wix/react-native-navigation全局添加网络状态拦截的实现思路

我之前在做RN项目时也碰到过类似需求,在wix/react-native-navigation这种组件独立注册的架构下,要给所有页面统一加全局逻辑,这里分享几个实操性强的方案,你可以根据项目情况选:

方案一:根组件全局控制(最推荐)

这种方式不用给每个页面单独加HOC,而是在导航根节点层面根据网络状态切换整个导航结构,逻辑集中,也不会出现重复跳转的问题。

步骤1:封装网络状态监听工具

先写个简单的工具类管理全局网络状态,方便后续组件获取和监听:

// utils/network.js
import NetInfo from '@react-native-community/netinfo';

let isConnected = true;
let listeners = [];

// 初始化网络监听
NetInfo.addEventListener(state => {
  const newConnected = state.isConnected && state.isInternetReachable;
  if (newConnected !== isConnected) {
    isConnected = newConnected;
    listeners.forEach(listener => listener(isConnected));
  }
});

// 订阅网络状态变化
export function subscribeNetworkChange(listener) {
  listeners.push(listener);
  return isConnected; // 立即返回当前状态
}

// 取消订阅
export function unsubscribeNetworkChange(listener) {
  listeners = listeners.filter(l => l !== listener);
}

// 获取当前网络状态
export function getNetworkStatus() {
  return isConnected;
}

步骤2:创建根控制组件AppRoot

这个组件作为应用入口,负责根据网络状态切换根导航布局:

// components/AppRoot.js
import React, { useEffect, useCallback } from 'react';
import { Navigation } from 'react-native-navigation';
import { subscribeNetworkChange, unsubscribeNetworkChange } from '../utils/network';

// 提前注册无网络页面
Navigation.registerComponent('NoNetworkScreen', () => require('./NoNetworkScreen').default);

// 正常网络下的标签页布局(替换成你自己的标签页配置)
const getTabLayout = () => ({
  root: {
    bottomTabs: {
      children: [
        {
          stack: {
            children: [{ component: { name: 'Home' } }],
            options: { bottomTab: { text: '首页' } }
          }
        },
        {
          stack: {
            children: [{ component: { name: 'Profile' } }],
            options: { bottomTab: { text: '我的' } }
          }
        }
        // 其他标签页...
      ]
    }
  }
});

// 无网络时的单页面布局
const getNoNetworkLayout = () => ({
  root: {
    stack: {
      children: [{ component: { name: 'NoNetworkScreen' } }]
    }
  }
});

export default function AppRoot() {
  useEffect(() => {
    // 初始化时设置初始布局
    const initialConnected = subscribeNetworkChange(handleNetworkChange);
    handleNetworkChange(initialConnected);

    // 组件卸载时取消监听
    return () => unsubscribeNetworkChange(handleNetworkChange);
  }, []);

  const handleNetworkChange = useCallback((isConnected) => {
    // 根据网络状态切换根导航
    if (isConnected) {
      Navigation.setRoot(getTabLayout());
    } else {
      Navigation.setRoot(getNoNetworkLayout());
    }
  }, []);

  // RN Navigation根组件无需渲染内容,靠setRoot控制布局
  return null;
}

步骤3:启动应用时注册根组件

把原来直接启动标签页的逻辑改成启动AppRoot:

// index.js
import { Navigation } from 'react-native-navigation';
import AppRoot from './components/AppRoot';

// 提前注册所有业务页面组件
Navigation.registerComponent('Home', () => require('./components/Home').default);
Navigation.registerComponent('Profile', () => require('./components/Profile').default);

// 启动根控制组件
Navigation.registerComponent('AppRoot', () => AppRoot);
Navigation.setRoot({
  root: {
    component: { name: 'AppRoot' }
  }
});

这个方案的优势是完全不修改现有页面代码,逻辑全集中在根组件,网络状态变化时直接切换整个导航根,用户体验很流畅。

方案二:给所有注册组件统一加HOC

如果你的项目还需要给每个页面加其他全局逻辑(比如登录态校验),可以用HOC统一包裹所有注册组件:

步骤1:编写网络检查HOC

// hoc/withNetworkCheck.js
import React, { useEffect, useRef } from 'react';
import { Navigation } from 'react-native-navigation';
import { getNetworkStatus, subscribeNetworkChange, unsubscribeNetworkChange } from '../utils/network';

export default function withNetworkCheck(WrappedComponent) {
  return function NetworkCheckHOC(props) {
    const isCurrentPageActive = useRef(true);

    useEffect(() => {
      const handleNetworkChange = (isConnected) => {
        // 仅当前页面活跃时处理跳转,避免重复跳转
        if (isCurrentPageActive.current && !isConnected) {
          Navigation.push(props.componentId, {
            component: { name: 'NoNetworkScreen' }
          });
        }
      };

      const initialConnected = subscribeNetworkChange(handleNetworkChange);
      if (!initialConnected) handleNetworkChange(false);

      return () => {
        unsubscribeNetworkChange(handleNetworkChange);
        isCurrentPageActive.current = false;
      };
    }, [props.componentId]);

    return <WrappedComponent {...props} />;
  };
}

步骤2:注册组件时统一使用HOC

把所有组件注册代码改成:

Navigation.registerComponent('Home', () => withNetworkCheck(require('./components/Home').default));
Navigation.registerComponent('Profile', () => withNetworkCheck(require('./components/Profile').default));
// 所有业务页面都用这个HOC包裹

注意:网络恢复后,需要在NoNetworkScreen里监听状态,调用Navigation.pop()或Navigation.popToRoot()回到原页面,避免用户手动返回时出现异常。

方案三:利用RN Navigation全局事件监听

如果需求简单,也可以通过监听全局页面显示事件来做拦截:

// 在App启动时添加全局监听
Navigation.events().registerComponentDidAppearListener(({ componentId, componentName }) => {
  // 排除无网络页面本身,避免死循环
  if (componentName === 'NoNetworkScreen') return;
  
  const isConnected = getNetworkStatus();
  if (!isConnected) {
    Navigation.push(componentId, {
      component: { name: 'NoNetworkScreen' }
    });
  }
});

这个方式最简洁,但缺点是无法处理页面后台时的网络变化,逻辑也比较分散,适合简单场景。

综合来看,方案一最适配你的需求,既不用改动现有页面,又能优雅控制全局导航切换。

内容的提问来源于stack exchange,提问作者Андрей Гузюк

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:23:12