devStandard/docs/learning/7-react/9-react-query.md
2025-03-29 14:35:49 +08:00

194 lines
5.0 KiB
Markdown
Executable File

# react-query
> 适用于 React Hooks 的请求库
> 远程数据的状态管理(也包括数据获取)
传统状态管理的缺点:
1. 远程数据无法控制
2. 需要写很多重复代码
3. 共享数据可能被修改
4. 数据可能过时
react-query的优点:
1. 缓存控制
2. 可以合并请求
3. 在后台更新过时数据
4. 知道数据什么时候过时
5. 分页和延迟加载等性能优化
6. 数据更新触发视图更新
7. 更好的内存回收
8. 存储更结构化并共享
## 文档
1. 官方文档: https://tanstack.com/query/latest/docs/react/overview
2. 中文翻译: https://cangsdarm.github.io/react-query-web-i18n/react/
3. 中文教程: https://juejin.cn/post/6937833844837974053
https://segmentfault.com/a/1190000041939135
## 安装
```bash
pnpm add @tanstack/react-query
```
兼容性:
```
Chrome >= 73
Firefox >= 78
Edge >= 79
Safari >= 12.0
iOS >= 12.0
opera >= 53
```
## 使用
三个重要概念: 查询, 修改, 主动查询失效
### 查询
1. 实例化 queryClient
2. 用 QueryClientProvider 包裹 app
```tsx
// main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import {
QueryClient,
QueryClientProvider,
} from '@tanstack/react-query'
const queryClient = new QueryClient()
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</React.StrictMode>
)
```
3. 用 useQuery 获取 异步数据
```tsx
/**
* useQuery
* - queryKey: 查询键, 是个数组, 通过不同的查询键来标识不同接口返回的不同数据, 简单理解成localstorage里的key
* - key内的元素可以是嵌套数组、对象、字符串、数字 ['zen', { form: 'confucius' }]
* - 从通用到特殊, 为了避免重复, 第一个可以是个字符串
* - 当key发生变化时, 会自动发起新的请求, 并缓存在新的key中
* - queryFn: 查询函数, 不只axios, fetch, 所有Promise都可以
* - 默认传参 {meta, pageParam, queryKey, signal}
* - 返回:
* - 状态只会是三种中的一种
* - isLoading: 加载状态
* - isError: 查询遇到一个错误
* - isSuccess: 查询成功,并且数据可用
* - data: 成功时的数据
* - error: 失败时的错误信息
*/
```
```tsx
import axios from 'axios'
import { useQuery} from '@tanstack/react-query'
type Props = {}
const StusList = (props: Props) => {
const getStudentsList = async (key:unknown)=>{
console.log('key:', key)
try {
const res = await axios.get('${window.apiUrl}/students')
return res.data
} catch (error) {
if(error instanceof Error){
return error.message
}
}
}
const { isLoading, isError, data, error } = useQuery(['studentsList'], getStudentsList)
return (
<>
{isLoading && <span>数据正在加载中...</span>}
{data && <span>{JSON.stringify(data)}</span>}
{isError && error instanceof Error && <span>{error.message}</span>}
{/* error 默认类型为unknown, 运行时进行检查 */}
</>
)
}
export default StusList
```
### 并行查询
```jsx
import axios from 'axios'
import { useState } from 'react'
import { useQuery } from '@tanstack/react-query'
const ParallelRequest = () => {
const user1Query = useQuery(['stuInfo', 1], () => {
return axios.get(`${window.apiUrl}/students/1`).then(res => res.data)
})
const user2Query = useQuery(['stuInfo', 2], () => {
return axios.get(`${window.apiUrl}/students/2`).then(res => res.data)
})
const query = useQuery(['stuInfo', '1&2'], () => {
return Promise.all([
axios.get(`${window.apiUrl}/students/1`).then(res => res.data),
axios.get(`${window.apiUrl}/students/2`).then(res => res.data),
])
})
return (
<div>
先完成先展示:
{user1Query.isLoading && <p>用户1正在加载中...</p>}
{user1Query.isError && <p>用户1数据获取错误!</p>}
{user1Query.data && <p>用户1数据:{JSON.stringify(user1Query.data)}</p>}
{user2Query.isLoading && <p>用户2正在加载中...</p>}
{user2Query.isError && <p>用户2数据获取错误!</p>}
{user2Query.data && <p>用户2数据:{JSON.stringify(user2Query.data)}</p>}
<br />
全部完成再展示:
{query.isLoading && <p>正在加载中...</p>}
{query.isError && <p>请求错误!</p>}
{query.data && <p>{JSON.stringify(query.data)}</p>}
</div>
)
}
export default ParallelRequest
```
第一部分 用户1, 用户2的数据, 谁先完成获取就展示谁
第二部分, 用户1 用户2全部获取完成后, 再进行展示, 在查询函数中使用了`Promise.all`
### 动态并行查询
> 查询数量在每次渲染时会发生变化, 不能使用手动查询, 使用`useQueries`
举例: 第一次查询`react, vue` 两个项目的仓库, 第二次查询 `selvte, ## Angular` 一个项目的仓库
### 修改
### 使查询失效
```tsx
```