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),所以 useEffectuseQuery 的默认挂载刷新不会执行。你需要这个钩子来手动触发。

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 负责具体的页面交互逻辑。

相关推荐
未来龙皇小蓝5 小时前
RBAC前端架构-01:项目初始化
前端·架构
程序员agions5 小时前
2026年,微前端终于“死“了
前端·状态模式
万岳科技系统开发5 小时前
食堂采购系统源码库存扣减算法与并发控制实现详解
java·前端·数据库·算法
程序员猫哥_5 小时前
HTML 生成网页工具推荐:从手写代码到 AI 自动生成网页的进化路径
前端·人工智能·html
龙飞055 小时前
Systemd -systemctl - journalctl 速查表:服务管理 + 日志排障
linux·运维·前端·chrome·systemctl·journalctl
我爱加班、、5 小时前
Websocket能携带token过去后端吗
前端·后端·websocket
AAA阿giao5 小时前
从零拆解一个 React + TypeScript 的 TodoList:模块化、数据流与工程实践
前端·react.js·ui·typescript·前端框架
杨超越luckly5 小时前
HTML应用指南:利用GET请求获取中国500强企业名单,揭秘企业增长、分化与转型的新常态
前端·数据库·html·可视化·中国500强
hedley(●'◡'●)6 小时前
基于cesium和vue的大疆司空模仿程序
前端·javascript·vue.js·python·typescript·无人机
qq5_8115175156 小时前
web城乡居民基本医疗信息管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
前端·vue.js·spring boot