什么是React Query
react-query
是一个适用于react hooks的请求库,它可以为任何类型的异步数据提供React状态管理功能,使React中的获取、缓存、同步和更新服务器数据变得轻而易举react-query
与一些传统的状态管理库如redux,mobx不同,它是负责管理服务器与客户端之间的状态,一些用户交互的中间状态,如loading状态,错误信息等都是通过hooks直接返回- React Query官网
初步使用
yarn add react-query
ornpm i react-query
安装react-query- 使用
QueryClientProvider
组件连接并提供一个QueryClient
到你的应用程序import { QueryClient, QueryClientProvider } from 'react-query' <QueryClientProvider client={new QueryClient()}> { ... } </QueryClientProvider>
Devtools
yarn add react-query-devtools
ornpm i --save react-query-devtools
安装Devtoolsreact-query-devtools
是与react-query
相匹配的开发工具- 可在开发中实时查看缓存,手动获取和删除查询等等
import { ReactQueryDevtools } from 'react-query-devtools' const App = () => { return ( <> { ... } <ReactQueryDevtools initialIsOpen={true} /> </> ); };
增删改查
- react-query最常用的两个hook,查询(
useQuery
)、增删改(useMutation
)
useQuery
useQuery
:在React Query
中,查询是对某些异步数据源的声明性依赖。查询可以与任何基于Promise的方法(GET)一起使用,从服务器获取数据const useTodos = (param) => { const request = useHttp() /** * 第一个参数是QueryKey,是查询的关键,是一个独一无二的key,并在之后的增删改中需要, * 如果需要动态的QueryKey,可以使用数组的方式,如['todos', params] * 第二个参数是用于获取数据的异步函数 * useQuery的响应返回就是获取到的数据和一些中间状态,如isLoading,error,isIdle... */ return useQuery('todos', () => request('todos', { data: param }) ) } // 在UI组件调用 const { isLoading, error, data: todos } = useTodos()
useMutation
useMutation
:常用于创建/更新/删除数据或执行服务器副作用const useAddTodo = () => { const request = useHttp() /** * 第一个参数是执行操作的异步函数,在返回的mutate中触发 * 第二个参数是执行成功或者失败的一些配置函数,可用于一些处理缓存的操作,例如乐观更新 */ return useMutation( (data) => request(`todos`, { data, method: 'POST', }), { onSuccess(){} onError(){} onSettled(){} ... } ) } // 操作组件调用 const TodosAddBtn = () => { ... const { mutateAsync, isLoading, error } = useAddTodo() return <Button onClick={() => mutateAsync(todoData)}>add</Button> }
例:用第二个参数配置乐观更新
- 乐观更新就是在一些请求或者数据处理没有结束的时候,提前给用户显示理想的结果,如果失败就回滚更新
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() {} } }
总结
- 本地/客户端中间状态
- redux与react-query都可,没有较大的优缺点
- 服务端中间状态
- 推荐react-query,将服务器状态从全局状态中解放出来,用更少的代码实现复杂的需求,让你的状态管理更优雅