React Native 数据同步双重奏:深度解析“页面级聚焦”与“应用级聚焦”的区别

引言

你是否遇到过这样的情况:用户在"个人中心"修改了头像,切回"首页"时头像却没变?或者用户早上打开了你的 App,下午切回来时看到的还是早上的旧新闻?

这并不是 Bug,而是 React Native 中数据同步机制缺失的表现。为了解决这些问题,我们需要手动配置 TanStack Query 的刷新时机。但最让人头疼的是:到底该监听 Screen 聚焦还是 App 聚焦?这两者有什么区别?

接下来的内容将为你彻底拆解这两个容易混淆的概念,让你根据业务需求精准控制数据刷新。

1. Refresh on Screen Focus (页面级聚焦)

代码片段:

TypeScript 复制代码
import React from 'react'
import { useFocusEffect } from '@react-navigation/native'
import { useQueryClient } from '@tanstack/react-query'

export function useRefreshOnFocus() {
  const queryClient = useQueryClient()
  const firstTimeRef = React.useRef(true)

  useFocusEffect(
    React.useCallback(() => {
      if (firstTimeRef.current) {
        firstTimeRef.current = false
        return
      }

      // refetch all stale active queries
      queryClient.refetchQueries({
        queryKey: ['posts'],
        stale: true,
        type: 'active',
      })
    }, [queryClient]),
  )
}
  • 触发时机: 当你在 App 内部 切换页面时。

    • 例如:你有一个底部的 Tab 栏(首页、我的)。
    • 动作:用户从"我的"页面点击 Tab 切换回"首页"。
  • 依赖库: 依赖 react-navigation (或 Expo Router) 的 useFocusEffect。

  • 原理:

    • React Navigation 会在页面进入视口(Visible)时触发回调。
    • 代码逻辑是手动 调用 queryClient.refetchQueries 去强制刷新指定的查询(如 ['posts'])。
  • 适用场景:

    • 用户在 Tab A 改了数据,切换到 Tab B 时,你希望 Tab B 立即更新。
    • 注意 :如果不加这个,在 React Navigation 中,仅仅切换 Tab 通常不会 触发组件的重新挂载(Re-mount),所以 useEffect 或 useQuery 的默认挂载刷新不会执行。你需要这个钩子来手动触发。

2. Refetch on App Focus (应用级聚焦)

代码片段:

TypeScript 复制代码
import { useEffect } from 'react'
import { AppState, Platform } from 'react-native'
import type { AppStateStatus } from 'react-native'
import { focusManager } from '@tanstack/react-query'

function onAppStateChange(status: AppStateStatus) {
  if (Platform.OS !== 'web') {
    focusManager.setFocused(status === 'active')
  }
}

useEffect(() => {
  const subscription = AppState.addEventListener('change', onAppStateChange)

  return () => subscription.remove()
}, [])
  • 触发时机: 当你 切换 App 或者 锁屏/解锁 时。

    • 例如:用户正在用你的 App,突然切出去回了个微信,或者接了个电话,然后又切回你的 App。
  • 依赖库: 依赖 React Native 原生的 AppState。

  • 原理:

    • 监听操作系统的状态变化(Background -> Active)。
    • 调用 focusManager.setFocused(true)。这是在告诉 TanStack Query 的全局大脑:"嘿,用户切回 App 了,你可以开始工作了。"
    • 它不会 指定刷新某一个 Query,而是自动检查所有处于 Active 状态且已过期(Stale)的 Query 并刷新它们。
  • 适用场景:

    • 保持数据的实时性(如社交媒体的时间流、股票价格)。
    • 防止用户长时间挂起 App 后看到过期的旧数据。

核心区别对比表

特性 Refresh on Screen Focus (第一段代码) Refetch on App Focus (第二段代码)
触发动作 切换 Tab / 页面跳转 (App 没关,只是切页面) 切换 App / 锁屏 (App 到了后台又回来)
范围 局部:通常只刷新当前页面的数据 全局:影响整个 App 所有活跃的查询
控制方式 手动 :代码里写死了要刷新 ['posts'] 自动 :Query 引擎根据 staleTime 自动决定刷新谁
核心依赖 @react-navigation/native react-native (AppState)
必须性 选配:取决于业务逻辑是否需要切 Tab 刷新 标配:建议在根组件配置,赋予 App 原生感知力

总结

  • 如果你想让用户从微信切回来 时刷新数据,用 Refetch on App Focus (写在 _layout.tsx)。
  • 如果你想让用户点底部 Tab 切换 时刷新数据,用 Refresh on Screen Focus(写在具体的页面组件里)。

最佳实践是:两者通常都需要。 全局配置负责 App 级别的活跃检测,局部 Hook 负责具体的页面交互逻辑。

相关推荐
石小石Orz8 分钟前
AI 正在蚕食我们的编码能力
前端·后端·算法
陈随易43 分钟前
专注飞机 FocusFlight,两个人把番茄钟做成了一趟航班
前端·后端·程序员
总要学点什么1 小时前
第98篇:三维特效-材质线效果——给一条线换十种材质,虚线的图案只填了一半
开发语言·前端·javascript·ecmascript·gis·webgl·材质
10share2 小时前
基于大模型的 i18n 方案:把中文原文当 Key,轻松搞定多语言维护
前端·vue.js
古茗前端团队4 小时前
由 key 引发的思考
前端·javascript·react.js
kyriewen4 小时前
我扫了 422 个仓库,近一半 CI 在裸装依赖
前端·javascript·程序员
鹏多多4 小时前
AI 到底能不能独立做个产品?我拿一个小程序验证了
前端·微信小程序·ai编程
火山引擎开发者社区4 小时前
构建专属的飞书群开发助手,AgentKit Studio 一键部署 DeepSeek Harness Super-Agent
前端
啾咪orJIUMI7 小时前
Vue 3 + 高德地图封装实战:点位、区域、Loca 流光与 Vue 信息窗体
前端·vue.js
掘金者阿豪7 小时前
AI数据库不只是向量检索:从数据语义到库内智能计算的技术演进
前端