在 React Native (RN) 开发中,你是否也曾被这些问题困扰:

  • **满屏的isLoading**:每个页面都要手写一遍 Loading 和 Error 逻辑。

  • 重复请求:切个页面回来,明明数据没变,却又发起了一次昂贵的网络请求。

  • 数据不同步:在 A 页面改了用户信息,回到 B 页面还是旧数据。

  • 手动缓存难:想做数据缓存,结果写了一堆 Redux 代码,维护起来像噩梦。

今天,我们要聊聊 **TanStack Query (原名 React Query)**。它被誉为 React 生态中“丢失的数据获取层”,能让你用最少的代码,解决最复杂的网络优化问题。

一、 为什么 RN 开发需要它?

很多人习惯把异步数据存在 Redux 或 Context 里。但本质上,Redux 是“全局状态管理”,而网络数据是“服务器状态”

服务器状态具有以下特点:

  1. 离线存储:数据不在你的控制下,随时可能过期。

  2. 异步获取:需要通过异步 API 更新。

  3. 共享性:多个组件可能同时依赖同一份数据。

React Query 正是为管理服务器状态而生的“智囊团”。

二、 核心原理:它在幕后做了什么?

React Query 的核心是一套智能缓存机制。我们可以用“图书馆借书”来类比:

  1. 查询(Query):你向 React Query 索要数据。

  2. 缓存(Cache):它先看缓存里有没有。如果有且数据“新鲜(Fresh)”,直接给你,不发请求。

  3. 失效(Stale):如果数据“陈旧(Stale)”,它会在后台静默发起请求,同时先给你旧数据垫底(保证用户不看白屏)。

  4. 同步(Refetch):新数据回来后,自动替换缓存并通知组件重新渲染。

三、 实战演练:三步走战略 1. 安装与初始化

首先,我们在 App 入口处包裹QueryClientProvider

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();

export default function App() {
return (

QueryClientProvider>
);
}

2. 获取数据(useQuery)

告别useState+useEffect的繁琐,现在只需要一行代码:

import { useQuery } from'@tanstack/react-query';

const fetchUser = async () => {
const res = await fetch('https://api.example.com/user');
return res.json();
};

function Profile() {
const { data, isLoading, isError, refetch } = useQuery({
queryKey: ['user'], // 缓存的唯一标识
queryFn: fetchUser, // 异步请求函数
});

if (isLoading) return;
if (isError) return;

return{data.name} Text>;
}

3. 修改数据(useMutation)

当你需要提交表单或删除数据时,使用useMutation

const mutation = useMutation({
mutationFn: updateUser,
onSuccess: () => {
// 关键点:数据改了,通知对应的缓存失效,触发自动刷新
queryClient.invalidateQueries({ queryKey: ['user'] });
},
});


四、 RN 专属优化进阶

在 React Native 中,有几个技巧能让你的应用丝滑到飞起:

1. 窗口聚焦重新获取 (Focus Refetching)

在 Web 端,切回标签页会自动刷新。在 RN 中,我们需要结合focusManager监听 App 状态:

import { focusManager } from '@tanstack/react-query';
import { AppState } from 'react-native';

focusManager.setEventListener((handleFocus) => {
const subscription = AppState.addEventListener('change', (status) => {
handleFocus(status === 'active');
});
return () => subscription.remove();
});

2. 离线缓存

配合persistQueryClient,可以将数据持久化到AsyncStorage中。即使用户断网打开 App,也能瞬间看到上次缓存的数据。

3. 预加载 (Prefetching)

当用户划过列表项时,提前预加载详情页数据。用户点击进入时,详情页近乎“秒开”。

五、 总结:为什么要选它?

功能

传统方式 (useEffect)

React Query

缓存管理

手写内存缓存/Redux

自动管理,支持过期配置

数据同步

困难,需手动分发 Action

自动失效并重新获取

Loading状态

每个页面手写 useState

内置 isLoading, isFetching

性能

易产生多余渲染

深度优化,按需渲染

核心箴言:把复杂的状态同步交给 React Query,把简单的 UI 逻辑留给自己。

如果你正在开发一款对性能和体验有追求的 RN 应用,React Query 不是可选项,而是必选项。

六、 核心 API 深度解析:掌控数据流 1.useQuery:精细化查询

这是最常用的 Hook,但它的强大全在options配置里。

const { data } = useQuery({
queryKey: ['user', userId], // 1. 唯一标识,userId 变化会自动触发重新请求
queryFn: () => fetchUser(userId),

// --- 进阶配置 ---
staleTime: 1000 * 60 * 5, // 5分钟内数据被认为是“新鲜”的,不触发后台刷新
cacheTime: 1000 * 60 * 30, // 缓存保留30分钟,即使没有组件使用它
enabled: !!userId, // 只有当 userId 存在时才发起请求(串行请求利器)
retry: 3, // 失败后自动重试3次
select: (data) => data.user, // 数据过滤,组件只会在 data.user 变化时才重渲
});

  • Query Key 的重要性:React Query 的缓存是基于 Key 的。你可以把它想象成一个 Map 的 Key。数组里的值(如userId)变化了,它就会被视为一个新的查询。

2.useMutation:副作用处理

处理增删改操作,它的核心在于生命周期回调

const mutation = useMutation({
mutationFn: (newTodo) => axios.post('/todos', newTodo),

onMutate: async (newTodo) => {
// 【高级技巧:乐观更新】
// 在请求发送前,手动修改缓存,让 UI 先变,如果失败再回滚
},
onSuccess: (data, variables, context) => {
// 操作成功后的动作,比如跳转页面
},
onError: (error, variables, context) => {
// 错误处理,比如弹出 Toast
},
onSettled: () => {
// 无论成功还是失败都会执行,类似 finally
}
});

3.QueryClient:全局指挥官

queryClient不仅仅用于Provider,它还是你手动干预缓存的“手术刀”。

  • **invalidateQueries**:暴力失效。告诉 React Query:“那个 Key 的数据旧了,去帮我重新拉一份。”

  • **setQueryData**:手动写缓存。不需要发请求,直接更新本地存的数据。

  • **getQueryData**:直接读取缓存中的数据(同步操作)。

七、 必须要懂的“数据状态”

在调试插件(DevTools)里,你会看到数据在不同状态间流转。理解这个闭环,你就理解了 React Query 的灵魂:

  1. **Fresh (新鲜)**:数据是最新的,直接用,不发请求。

  2. **Stale (陈旧)**:数据可用,但已经“过期”。你用它的同时,React Query 会悄悄在后台发请求同步。

  3. **Fetching (获取中)**:正在网络传输。

  4. **Inactive (非活跃)**:页面卸载了,数据暂时没人用,等着被垃圾回收(GC)。

给读者的避坑指南:
  • 不要在queryFn里写逻辑:保持它纯净,只负责 fetch 数据。

  • **合理设置staleTime**:RN 应用通常不需要实时性极高。将staleTime设置为 1-2 分钟,能显著降低服务器压力并提升 App 流畅度。

好的,这份思维导图采用了 Markdown 格式,逻辑清晰,涵盖了从基础概念到进阶优化的所有重点。你可以直接将这段代码贴到支持 Markdown 的编辑器(如 Typora、Obsidian)中,或者直接作为公众号文章的总结大纲。

TanStack Query (React Query) 核心知识体系 1. 核心定位

  • 本质:异步状态管理利器(Async State Manager)。

  • 目标:将“服务器状态”与“客户端状态”分离。

  • RN 痛点解决:自动缓存、数据同步、离线支持、减少无效请求。

2. 三大基石 API
  • useQuery(读)

  • queryKey: 缓存的唯一指纹(数组格式)。

  • queryFn: 必须返回 Promise 的异步函数。

  • staleTime: 数据从“新鲜”变“陈旧”的时间。

  • cacheTime: 内存缓存保留时间(默认 5 分钟)。

  • enabled: 控制请求开关(实现串行请求、按需请求)。

  • useMutation(写)

  • mutationFn: 处理 POST/PUT/DELETE。

  • 生命周期:onMutate(乐观更新)、onSuccessonErroronSettled

  • QueryClient(管)

  • invalidateQueries: 主动标记缓存失效,触发静默刷新。

  • setQueryData: 直接手动更新缓存内容。

  • prefetchQuery: 预加载,提升页面切换速度。

3. 缓存生命周期 (States)
  • Fresh (新鲜): 直接读取缓存,不触发网络请求。

  • Stale (陈旧): 先给缓存数据,同时后台静默发起请求同步。

  • Fetching (获取中): 正在进行网络请求。

  • Inactive (未激活): 组件已卸载,数据等待 GC(垃圾回收)。

4. RN 专属优化点
  • Focus Refetch: 配合AppState实现 App 切回前台时自动刷新。

  • Online Manager: 监听网络状态,断网重连后自动重试。

  • Persistence: 结合AsyncStorage实现数据离线持久化。

5. 性能秘籍
  • Select: 在 Hook 层进行数据过滤,减少组件不必要的重绘。

  • Placeholder Data: 使用占位数据(如旧数据)避免全屏 Loading。

  • Optimistic Updates: 乐观更新,让操作在网络返回前就完成 UI 变化。

React Query 的精髓不在于如何发起请求,而在于它如何通过一套优雅的协议,让开发者不再关心‘什么时候发请求’和‘怎么同步数据’。掌握了它,你的 RN 开发效率将提升一个量级。