Expo 进阶指南:赋予 TanStack Query “原生感知力” —— 深度解析 AppState 与 NetInfo

在 Web 开发中,我们习惯了浏览器的"智能":切换标签页时页面会自动刷新,断网重连后请求会自动重试。这是因为浏览器底层自动处理了窗口聚焦(Window Focus)和网络状态(Online Status)的事件。

然而,在 React Native (Expo) 环境中,App 默认是"盲"和"聋"的。TanStack Query 不知道用户什么时候把 App 切到了后台,也不知道手机什么时候断了网。

为了让 App 拥有极致的用户体验(如:切回来自动刷新、断网自动暂停重试),我们需要手动配置 "感官系统" 。本文将深入解读 AppStateStatussetOnline,并提供生产环境的完整配置方案。


一、 深度解读:App 的"感官系统"

1. 视觉神经:AppStateStatus (应用状态)

AppStateStatus 是 React Native 原生提供的一个状态类型,用于描述 App 当前处于什么处境。

三个核心状态:

  • active (前台/活跃) :用户正在盯着屏幕,App 在最上层运行。这是我们唯一希望触发数据刷新的状态。
  • background (后台) :用户按了 Home 键,或者切换到了微信。App 还在内存中运行,但界面不可见。
  • inactive (非活跃) :App 处于"半死不活"的过渡态(如被来电画面覆盖、拉下了通知栏、iOS 多任务切换界面)。

为什么要配置它?

TanStack Query 有一个核心功能叫 Window Focus Refetching。

  • 问题 :RN 默认没有 window.onfocus 事件。
  • 解决 :我们需要监听 AppState 的变化。当状态变为 active 时,手动调用 focusManager.setFocused(true)
  • 效果:TanStack Query 收到信号后,会立即检查页面上的数据是否过期(Stale)。如果过期,它会在后台悄悄发起请求,用户切回来的一瞬间看到的就是最新数据。

2. 听觉神经:setOnline (联网回调)

setOnline 不是一个你可以直接导入的函数,它是 TanStack Query 的 onlineManager.setEventListener 方法传递给你的一个回调函数(参数)。你可以把它理解为 TanStack Query 递给你的一把"开关"。

逻辑流程图:从断网到重连

lua 复制代码
+---------------------------+
| 📡 物理层                  |
| 手机 4G/WiFi 信号变化       |
+-------------+-------------+
              |
              v (触发系统事件)
+-------------+-------------+
| 🎧 B: NetInfo 监听器       |
+-------------+-------------+
              |
              v (获取状态: isConnected)
+-------------+-------------+
| 💻 C: 开发者代码逻辑        |
| (app/_layout.tsx)         |
+-------------+-------------+
              |
              v (调用 setOnline)
+-------------+-------------+
| ⚙️ D: TanStack Query      |
|     (onlineManager)       |
+-------------+-------------+
       /             \
      / (false)       \ (true)
     v                 v
+---------+       +---------+
| E: 🛑   |       | F: 🚀   |
| 暂停     |       | 恢复    |
| (Pause) |       | (Resume)|
| 停止重试 |       | 立即重试 |
+---------+       +---------+

为什么要配置它?

  • 省电保护:如果没配置,断网时 TanStack Query 会傻傻地一直重试请求,消耗用户电量。配置后,断网即休眠。
  • 体验优化 :如果没配置,网络恢复后,App 不会有反应,用户必须手动下拉刷新。配置后,信号恢复的瞬间,数据自动加载成功("电梯效应")。

二、 生产环境完整配置 (app/_layout.tsx)

这是融合了上述原理的完整配置代码。请确保你已安装了 @react-native-community/netinfo

TypeScript 复制代码
import { useEffect } from 'react';
import { AppState, AppStateStatus, Platform } from 'react-native';
import { Slot } from 'expo-router';
import NetInfo from '@react-native-community/netinfo';
import { 
  QueryClient, 
  QueryClientProvider, 
  focusManager, 
  onlineManager 
} from '@tanstack/react-query';

// =================================================================
// 1. 配置网络监听 (给 App 装上"耳朵")
// =================================================================
onlineManager.setEventListener((setOnline) => {
  // setOnline 是 Query 传进来的一个函数,用来接收网络状态
  // 我们使用 NetInfo 来监听真实的网络变化
  return NetInfo.addEventListener((state) => {
    // state.isConnected 可能为 null,用 !! 强转为 boolean
    // 当这里调用 setOnline(true) 时,Query 会立即重试刚才失败的请求
    setOnline(!!state.isConnected);
  });
});

// =================================================================
// 2. 配置 App 状态监听 (给 App 装上"眼睛")
// =================================================================
function onAppStateChange(status: AppStateStatus) {
  // Web 浏览器会自动处理窗口聚焦,只有原生 App 需要手动处理
  if (Platform.OS !== 'web') {
    // 核心逻辑:
    // 当 AppState 变为 'active' (前台) 时
    // 我们手动告诉 Query 的 focusManager:"用户现在聚焦在 App 上了"
    // Query 收到信号后,会检查页面数据是否过期 (stale),如果过期则自动 Refetch
    focusManager.setFocused(status === 'active');
  }
}

// =================================================================
// 3. 初始化 QueryClient (配置全局策略)
// =================================================================
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      retry: 2,             // 失败后自动重试 2 次
      staleTime: 1000 * 60, // 数据 1 分钟内算"新鲜",切回来也不刷新
                            // 超过 1 分钟后切回来,会触发自动刷新
    },
  },
});

export default function RootLayout() {
  // 注册 AppState 监听器
  useEffect(() => {
    // 开始监听系统状态变化
    const subscription = AppState.addEventListener('change', onAppStateChange);
    
    // 组件卸载时取消监听,这是防止内存泄漏的标准做法
    return () => subscription.remove();
  }, []);

  return (
    
      {/* Slot 是 Expo Router 的页面入口 */}
      
    
  );
}

三、 总结

在 React Native 中使用 TanStack Query,90% 的人只做了"安装",而忽略了"配置"

如果不配置这两个管理器,你的 App 就失去了灵魂:

  1. AppStateStatus + focusManager :让 App 知道"我醒了",从而实现微信切回来的自动刷新。
  2. setOnline + onlineManager :让 App 知道"我有网了",从而实现走出电梯后的自动重连。

只要在 _layout.tsx 中写好配置代码,你应用里所有的 useQuery 就都自动拥有了这些原生级别的感知能力。这就是从"能用"到"好用"的关键跨越。

相关推荐
Moment3 小时前
从美团全栈化看 AI 冲击:前端转全栈,是自救还是必然 🤔🤔🤔
前端·后端·面试
天问一3 小时前
使用 Vue Router 进行路由定制和调用的示例
前端·javascript·vue.js
韩立学长4 小时前
【开题答辩实录分享】以《基于Vue的非遗文化知识分享平台的设计与实现》为例进行选题答辩实录分享
前端·javascript·vue.js
优弧4 小时前
离开舒适区100天,我后悔了吗?
前端·后端·面试
胡gh4 小时前
css的臂膀,前端动效的利器,还是布局的“隐形陷阱”?
前端·css·html
灵感菇_5 小时前
Flutter Riverpod 完整教程:从入门到实战
前端·flutter·ui·状态管理
用户21411832636025 小时前
紧急修复!Dify CVE-2025-55182 高危漏洞,手把手教你升级避坑
前端
Vic101015 小时前
解决 Spring Security 在异步线程中用户信息丢失的问题
java·前端·spring
wordbaby6 小时前
Expo (React Native) 最佳实践:TanStack Query 深度集成指南
前端·react native