一、 react-query介绍
1.1 react-query是什么
react-query是一个异步状态管理的hook,内置了loading,error等状态。
1.2 react-query的作用
- 封装了loading、error等方便使用,减少代码量
- 多个组件请求同一个query时只发送一个请求
- 缓存更新和时效策略
1.3 react-query和redux的区别
react-query和redux都能进行状态管理和异步数据的处理,react-query更偏向于服务器之间的异步数据的管理
1.4、概览
没使用react-query之前,你的代码可能是这样的
import { useEffect, useState, useMemo, memo } from 'react';
const fetchList = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const list = [
{ id: '1', name: 'banana' },
{ id: '2', name: 'orange' },
{ id: '3', name: 'apple' },
{ id: '4', name: 'strawberry' },
{ id: '5', name: 'grape' },
];
resolve({ data: list })
}, 1000);
});
};
function List() {
const [list, setList] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
setLoading(true);
fetchList().then(res => {
setLoading(false);
setList(res?.data)
}).catch(err => setLoading(false))
}, []);
const renderList = useMemo(() => {
return list.map(l => <div key={l.id}>
{l.name}
</div>);
}, [list]);
return (
<div className='list'>
{loading ? 'loading' : renderList}
</div>
);
}
function App(){
return <div className='app'>
<List/>
</div>
};
export default memo(App);
使用react-query
import { memo } from 'react';
import { useQuery, QueryClientProvider, QueryClient } from 'react-query';
const fetchList = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const list = [
{ id: '1', name: 'banana' },
{ id: '2', name: 'orange' },
{ id: '3', name: 'apple' },
{ id: '4', name: 'strawberry' },
{ id: '5', name: 'grape' },
];
resolve({ data: list })
}, 1000);
});
};
function List() {
const { isLoading, error, data } = useQuery('getListData', () => fetchList().then(res => res.data));
if (error) {
return 'An error has occurred: ' + error.message
}
if (isLoading) {
return 'data is loading.'
}
return data.map(l => <div key={l.id}>
{l.name}
</div>);
}
function App() {
const queryClient = new QueryClient();
return <div className='app'>
<QueryClientProvider client={queryClient}>
<List />
</QueryClientProvider>
</div>
};
export default memo(App);
多个组件请求同一个query只会进行一次请求
function List() {
const { isLoading, error, data } = useQuery('getListData', () => fetchList().then(res => res.data));
if (error) {
return 'An error has occurred: ' + error.message
}
if (isLoading) {
return 'data is loading.'
}
return data.map(l => <div key={l.id}>
{l.name}
</div>);
}
function List1() {
const { isLoading, error, data } = useQuery('getListData', () => fetchList().then(res => res.data));
if (error) {
return 'An error has occurred: ' + error.message
}
if (isLoading) {
return 'data is loading.'
}
return data.map(l => <div key={l.id}>
{l.name}
</div>);
}
function App() {
const queryClient = new QueryClient();
return <div className='app'>
<QueryClientProvider client={queryClient}>
<List />
<List1/>
<ReactQueryDevtools initialIsOpen={false} position='top-right'/>
</QueryClientProvider>
</div>
List和List1都使用了getListData这个query,但最终只会请求一次
二、基础使用
2.1 useQuery
useQuery接收两个参数,第一个是唯一表示key,第二个是一个fetch的异步函数。key是一个唯一的字符串,用来标识query,key还可以是个数组,存放query依赖的一些变量,类似于useMemo和useCallback,当依赖发生变化时会重新发起请求
const [id, setId] = useState(0)
const { isLoading, error, data, state, isFetching } = useQuery(['getListData', id],
() => fetchList(id).then(res => res.data));
if (error) {
return 'An error has occurred: ' + error.message
}
if (isLoading) {
return 'data is loading.'
}
return <div>
{data.map(l => <div key={l.id}>
{l.name}
</div>)}
<button onClick={() => setId(id + 1)}>按钮</button>
</div>;
2.2 useMutation
useMutation的主要作用是清除缓存,更新和删除数据
const queryClient = useQueryClient();
// Mutations
const mutation = useMutation(removeList, {
onSuccess: () => {
// Invalidate and refetch
queryClient.invalidateQueries('getListData')
},
});
<button onClick={()=> mutation.mutate({id:'0',text:'文字'})}>按钮</button>
2.3 使用devtools
import { ReactQueryDevtools } from 'react-query/devtools';
function App() {
const queryClient = new QueryClient();
return <div className='app'>
<QueryClientProvider client={queryClient}>
<List />
<List1/>
<ReactQueryDevtools initialIsOpen={false} position='top-right'/>
</QueryClientProvider>
</div>
};
2.4 乐观更新
乐观更新就是在一些请求或者数据处理没有结束的时候,提前给用户显示理想的结果,如果失败就回滚更新
const useAddConfig = (queryKey) => {
// 获取当前QueryClient的实例
const queryClient = useQueryClient()
return {
// 当mutate被调用时触发
async onMutate(target) {
// 获取当前数据快照,用于错误时回滚更新
const previousItems = queryClient.getQueryData(queryKey)
// 乐观更新为新值
queryClient.setQueryData(queryKey, (old) => {
return (target, old) => (old ? [...old, target] : [])
})
// 这个返回值会作为最后一个参数传递给onError和onSettled
return { previousItems }
},
// 成功回调 清除缓存
onSuccess: () => queryClient.invalidateQueries(queryKey),
// 失败回调
onError(error, newItem, context) {
// 当前queryKey的数据回滚
queryClient.setQueryData(
queryKey,
context.previousItems
)
},
// 无论错误或者成功都会触发,此例子没有使用
onSettled() {}
}
}
传送门:react-query官网