194 lines
5.0 KiB
Markdown
Executable File
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
|
|
|
|
``` |