Skip to content

Commit c8b1a6d

Browse files
committed
新增TanStack Query
1 parent dba9b27 commit c8b1a6d

File tree

2 files changed

+141
-1
lines changed

2 files changed

+141
-1
lines changed

docs/index.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
- [Vue中快速定义Props属性的函数封装 --- 2022/08](/share/props.html)
1616

1717
- [在JavaScript中实现style的CanIUse --- 2022/08](/share/canIUseStyle.html)
18-
-
18+
1919
- [在不使用Event Bus来实现深层组件嵌套事件通信 --- 2023/08](/share/event.html)
2020

21+
- [TanStack Query 入门食用指南 --- 2024/01](/share/query.html)
22+
2123
### 踩坑 🧐
2224

2325
- [pdf.js踩坑(基于webpack下的pdfjs-dist库) --- 2022/06](/bug/pdfjs.md)

docs/share/query.md

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# TanStack Query 入门食用指南
2+
3+
对常见的请求场景进行一个封装,可以跨组件的管理请求状态,并且支持多个框架版本。
4+
5+
由于V5版本只有纯英文文档,因此在进行阅读后记录它的基本用法,哪天用到了可以快速使用。
6+
7+
本篇记录的是`react-query`的用法,其它版本大差不差。
8+
9+
### QueryClient && QueryClientProvider
10+
11+
```tsx
12+
const queryClient = new QueryClient()
13+
14+
ReactDOM.createRoot(document.getElementById('root')!).render(
15+
<React.StrictMode>
16+
<QueryClientProvider client={queryClient}>
17+
<App/>
18+
</QueryClientProvider>
19+
</React.StrictMode>,
20+
)
21+
```
22+
23+
实例化`QueryClient`类,并使用`QueryClientProvider`组件注入后,所有子组件就可以通过`useQueryClient`来进行跨组件操作。
24+
25+
### useQuery
26+
27+
`query`一般用于`get`请求的场景,页面加载就可以发起请求。
28+
29+
```typescript
30+
const [enabled, setEnabled] = useState(false)
31+
32+
const { isPending, isFetching, isLoading, data, refetch } = useQuery({
33+
// 这里可以放不同的数据类型,一般可以将组件的state放进去
34+
queryKey: ['useQuery'],
35+
// 这里会传入一些参数
36+
queryFn: ({ queryKey }) => axios().then((response) => {
37+
// 这里需要自行处理response得到的数据,最后就会放到data中
38+
return response
39+
}),
40+
enabled,
41+
placeholderData: keepPreviousData,
42+
initialData: initialData
43+
})
44+
```
45+
46+
- `queryFn`为请求函数,无论是使用`fetch`还是`axios`只要是返回`Promise`都可以使用。在调用`queryFn`时,`queryKey`会作为参数上下文中的`queryKey`传给`queryFn`
47+
当需要将请求状态更改为`error`状态时可以在`Promise`内返回`reject``throw new Error`
48+
49+
- `queryKey`可以用于在其它地方通过`queryClient`调用或通过其定义的`queryKey`在变更时重新发起请求,`queryKey`的数组内支持数字,字符串以及可序列化的对象。
50+
51+
- `useQuery`会返回请求的状态以及数据源,这里需要注意`isPending``isFetching`的区别,`isPending``devtools/network``pending`不同,
52+
它代表的是数据的获取状态,`isFetching`才是请求的状态。`isLoading``isPending && isFetching`的计算值,一般用于惰性发起请求。
53+
54+
#### 惰性请求
55+
56+
- 当需要惰性(也可以说是根据条件决定)发起请求时,可以定义`enabled`为组件的`state`,然后将`state`放入`queryKey`当中,也可以从`useQuery`内使用`refetch`来手动发起请求,不过官方并不推荐手动发起。
57+
58+
#### 分页场景
59+
60+
- 在分页场景下,可以定义`placeholderData`属性,可以使用自带的`keepPreviousData`或自定义返回值,这样在切换分页时,在新数据获取之前,可以保留旧的数据。
61+
这个属性可以理解为分页场景下的`placeholder`
62+
63+
#### 初始数据
64+
65+
- 如果想在发起请求之前放一些假数据或从其它地方得到的数据在那,那么可以定义`initialData`,数据类型要和`data`内的相同,支持直接定义或函数返回。
66+
67+
### useInfiniteQuery
68+
69+
```typescript
70+
const { data, fetchNextPage, fetchPreviousPage, hasNextPage } = useInfiniteQuery({
71+
queryKey: ['infinite'],
72+
queryFn: ({ pageParam }) => axios(pageParam).then((res) => res.data),
73+
initialPageParam: {
74+
page: 1,
75+
size: 10
76+
},
77+
getNextPageParam: (lastPage, allPage, pageParam) => {
78+
// 在此返回下一页的pageParam
79+
},
80+
getPreviousPageParam: () => {
81+
// 用法与getNextPageParam一致,但不是必填项
82+
}
83+
})
84+
```
85+
86+
- `queryKey``queryFn``useQuery`的用法基本一致,不过`queryFn`中多了一个`pageParam`参数可供使用。
87+
88+
- 使用`useInfiniteQuery`时必须传入`initialPageParam``getNextPageParam``initialPageParam`为发起请求的初始值,一般为页码和页数或只有页码。
89+
`getNextPageParam`用于获取下一页数据(如调用了`fetchNextPage`)时的`pageParam`,如果后端提供了`下一页`的字段,那么可以直接使用,若未提供则需要手动对页数进行`+1`
90+
91+
- `hasNextPage``getNextPageParam`返回值,不为`undefined``null`时都为`true`
92+
93+
- 对应`NextPage``useInfiniteQuery`也提供了`getPreviousPageParam`以及其它和`NextPage`相似的功能,不过需要注意的是,`getPreviousPageParam`不是获取上一页,而是从头部插入数据。
94+
95+
-`data`上和`useQuery`不同,`data`则变为一个对象,包含`page``pageParams`,前者是请求获取的数据源,后者则是每次`Next``Previous`所得到的`pageParam`
96+
97+
- 需要注意的是这里的`page`是由每一次获取到的数据一起拼接而成,是一个二维或多维数组,在使用时需注意使用方式。
98+
99+
```tsx
100+
{
101+
data?.pages.map((group, index) => (
102+
<Fragment key={index}>
103+
{/*这里才是请求到的数据*/}
104+
{group.map((item) => <p key={item.value}>{item.label}</p>)}
105+
</Fragment>
106+
))
107+
}
108+
```
109+
110+
### useMutation
111+
112+
常用于`post`场景,需手动发起。
113+
114+
```typescript
115+
const { mutateAsync, mutate, isPending, isSuccess } = useMutation({
116+
mutationKey: ['useMutation'],
117+
mutationFn: (params) => axios(params),
118+
onMutate: () => {},
119+
onSuccess: () => {},
120+
onError: () => {},
121+
onSettled: () => {}
122+
})
123+
```
124+
125+
- `mutationKey``mutationFn``query`中的用法基本一致,`mutationFn`的参数来自于`mutate``mutateAsync`传递的值。
126+
127+
- `useMutation`具有独特的回调事件,`onMutate`可以理解为发起请求前需要进行的操作,其余三个回调事件可以对应理解为`Promise`中的`then``catch``finally`
128+
129+
- `mutate``mutateAsync`的使用方法一致,区别是若想触发`useMutation`上定义的回调之外的其他回调,`mutateAsync`可以向使用`Promise`那样注册`then/catch/finally`
130+
`mutate`需要作为第二个参数传入其回调事件。
131+
132+
```typescript
133+
mutate(params, {
134+
onSuccess: () => {},
135+
onError: () => {},
136+
onSettled: () => {}
137+
})
138+
```

0 commit comments

Comments
 (0)