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

相关推荐
ModyQyW21 小时前
HBuilderX 4.87 无法正常读取 macOS 环境配置的解决方案
前端·uni-app
bitbitDown21 小时前
我的2025年终总结
前端
五颜六色的黑21 小时前
vue3+elementPlus实现循环列表内容超出时展开收起功能
前端·javascript·vue.js
wscats1 天前
Markdown 编辑器技术调研
前端·人工智能·markdown
EnoYao1 天前
Markdown 编辑器技术调研
前端·javascript·人工智能
JIngJaneIL1 天前
基于java+ vue医院管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot
JIngJaneIL1 天前
基于java + vue校园跑腿便利平台系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot
前端要努力1 天前
月哥创业3年,还活着!
前端·面试·全栈
sao.hk1 天前
ubuntu2404安装k3s
前端·chrome
cos1 天前
Worktrunk 完全指南:让 Git Worktree 和 Claude Code 和平共处
前端·ai编程·claude