什么是 RTK Query?
RTK Query 是 Redux Toolkit 官方提供的数据获取和缓存解决方案 。它专为解决现代应用中的数据获取需求而设计,通过自动化缓存管理、数据获取和状态更新,显著减少数据管理所需的样板代码。
核心优势
- ⚡️ 零配置数据缓存:自动管理缓存生命周期
- 📦 内置加载状态:自动跟踪请求状态(loading/success/error)
- 🔄 自动数据同步:通过标签系统实现自动刷新
- 🔌 高度可扩展:轻松与现有 Redux 逻辑集成
- 🧩 TypeScript 优先:提供完整的类型安全支持
快速入门指南
安装依赖
bash
npm install @reduxjs/toolkit react-redux
基础使用示例
1. 创建 API 服务
javascript
// apiSlice.js
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
export const apiSlice = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
tagTypes: ['Post'], // 定义标签类型
endpoints: (builder) => ({
getPosts: builder.query({
query: () => '/posts',
providesTags: ['Post'] // 为此查询提供'Post'标签
}),
addPost: builder.mutation({
query: (newPost) => ({
url: '/posts',
method: 'POST',
body: newPost
}),
invalidatesTags: ['Post'] // 使所有'Post'标签失效
})
})
})
export const { useGetPostsQuery, useAddPostMutation } = apiSlice
2. 配置 Redux Store
javascript
// store.js
import { configureStore } from '@reduxjs/toolkit'
import { apiSlice } from './apiSlice'
export const store = configureStore({
reducer: {
[apiSlice.reducerPath]: apiSlice.reducer
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(apiSlice.middleware)
})
3. 在组件中使用
jsx
// PostsComponent.jsx
import { useGetPostsQuery, useAddPostMutation } from './apiSlice'
function Posts() {
const { data: posts, isLoading, isError } = useGetPostsQuery()
const [addPost] = useAddPostMutation()
const handleSubmit = async () => {
await addPost({ title: 'New Post', content: 'RTK Query is awesome!' })
}
if (isLoading) return <div>Loading...</div>
if (isError) return <div>Error loading posts</div>
return (
<div>
<button onClick={handleSubmit}>Add Post</button>
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
)
}
与 Axios 集成(自定义 baseQuery)
RTK Query 默认使用 fetchBaseQuery
(基于 Fetch API),但可以轻松集成 Axios:
javascript
// axiosBaseQuery.js
import axios from 'axios';
const axiosBaseQuery = ({ baseUrl } = { baseUrl: '' }) =>
async ({ url, method, data, params }) => {
try {
const result = await axios({
url: baseUrl + url,
method,
data,
params
})
return { data: result.data }
} catch (axiosError) {
return {
error: {
status: axiosError.response?.status,
data: axiosError.response?.data || axiosError.message
}
}
}
}
// 在 createApi 中使用
export const apiSlice = createApi({
reducerPath: 'api',
baseQuery: axiosBaseQuery({ baseUrl: '/api' }),
// ...其他配置
})
RTK Query 与 Redux 的关系
RTK Query 是 Redux Toolkit 生态系统的一部分:
- 构建在 Redux 之上:使用 Redux store 存储所有状态
- 无缝集成:与现有 Redux 逻辑并存,共享同一个 store
- 自动生成 reducer 和 action:无需手动编写 reducer 逻辑
- 中间件驱动:使用自定义中间件管理缓存生命周期
graph TD
A[React组件] --> B[使用 useQuery/useMutation]
B --> C[RTK Query API]
C --> D[Redux Store]
D --> E[自动管理状态]
E --> F[缓存/加载/错误状态]
自动化缓存管理:标签系统
RTK Query 的标签系统是其最强大的特性之一,通过 providesTags
和 invalidatesTags
实现自动缓存失效和重新获取。
标签系统工作原理
-
标记数据关系:
javascriptendpoints: builder => ({ getPosts: builder.query({ query: () => '/posts', providesTags: ['Post'] // 此查询提供'Post'标签 }), addPost: builder.mutation({ query: (post) => ({ /* ... */ }), invalidatesTags: ['Post'] // 使所有'Post'标签失效 }) })
-
精确缓存控制(使用 ID):
javascriptgetPost: builder.query({ query: (id) => `/posts/${id}`, providesTags: (result, error, id) => [{ type: 'Post', id }] }), updatePost: builder.mutation({ query: ({ id, ...patch }) => ({ url: `/posts/${id}`, method: 'PATCH', body: patch }), invalidatesTags: (result, error, { id }) => [{ type: 'Post', id }] })
-
组合标签:
javascriptgetUserPosts: builder.query({ query: (userId) => `/users/${userId}/posts`, providesTags: (result, error, userId) => result ? [ ...result.map(post => ({ type: 'Post', id: post.id })), { type: 'UserPosts', id: userId } ] : ['UserPosts'] })
当执行变更操作(mutation)时,所有关联的标签会自动失效,触发相关查询的重新获取。
对比其他状态管理方案
特性 | RTK Query | Redux + Thunk/Saga | React Query | SWR |
---|---|---|---|---|
学习曲线 | 中等 (需Redux知识) | 高 | 低 | 低 |
缓存管理 | 自动 | 手动 | 自动 | 自动 |
数据获取抽象 | 高级抽象 | 低级实现 | 高级抽象 | 高级抽象 |
与Redux集成 | 原生支持 | 原生支持 | 需要额外集成 | 需要额外集成 |
自动重新获取 | 通过标签系统 | 手动实现 | 通过键/依赖 | 通过键/依赖 |
加载状态管理 | 自动 | 手动 | 自动 | 自动 |
变更操作 | 内置mutation | 手动实现 | 内置mutation | 需要额外实现 |
RTK Query 的独特优势
-
Redux 生态集成:
- 与现有 Redux store 无缝协作
- 可直接访问 Redux DevTools 调试
- 与 Redux Thunk/其他中间件兼容
-
极少的样板代码:
javascript// 传统 Redux 异步 action const fetchPosts = () => (dispatch) => { dispatch(postsLoading()) axios.get('/posts') .then(res => dispatch(postsReceived(res.data))) .catch(err => dispatch(postsFailed(err.message))) } // RTK Query 等效实现 getPosts: builder.query({ query: () => '/posts' })
-
智能缓存策略:
- 相同请求的自动去重
- 组件卸载后保留数据缓存
- 窗口重新聚焦时自动刷新
-
自动生成的 React Hooks:
useQuery
:处理数据获取useMutation
:处理数据变更useLazyQuery
:按需触发查询
降低上手门槛的技巧
-
利用代码生成:从 OpenAPI/Swagger 规范自动生成 API slice
bashnpx @rtk-query/codegen-openapi openapi-config.json
-
从简单场景开始:
javascript// 最小化配置 export const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: '/api' }), endpoints: () => ({}) })
-
逐步添加标签:
- 开始时可以不使用标签
- 需要缓存失效时再添加
providesTags/invalidatesTags
-
重用查询参数:
jsx// 在多个组件中使用相同查询 function ComponentA() { const { data } = useGetPostsQuery() // ... } function ComponentB() { // 自动重用缓存数据 const { data } = useGetPostsQuery() // ... }
-
高级场景处理:
javascript// 条件查询 const { data } = useGetPostQuery(id, { skip: !id // 当id不存在时跳过查询 }); // 轮询查询 const { data } = useGetPostsQuery(undefined, { pollingInterval: 5000 // 每5秒刷新一次 });
总结
RTK Query 彻底改变了 Redux 应用中的数据管理方式:
- 🚀 减少约 80% 的数据管理样板代码
- 🔄 通过标签系统实现智能缓存管理
- ⚙️ 无缝集成现有 Redux 架构
- 📡 支持多种通信协议(REST/GraphQL/WebSockets)
- 🧪 提供完整的类型安全(TypeScript)
对于已经在使用 Redux 的项目,RTK Query 提供了最平滑的数据获取升级路径。即使是不熟悉 Redux 的开发者,也能通过其简洁的 API 快速上手高效的数据管理。
开始尝试 RTK Query,体验现代 React 应用数据管理的最佳实践!
官方资源: