React library 快速入门——React Query
前言
React的生态非常庞大,各种lib层出不穷,本系列将介绍其中最受欢迎的一些lib,并给出快速入门的实践案例。
本期介绍的是React Query。
概览
React Query是一个管理请求数据的库。
React Query is often described as the missing data-fetching library for React, but in more technical terms, it makes fetching, caching, synchronizing and updating server state in your React applications a breeze.
看官网解释可能有些费解,上代码:
import React from "react"; import ReactDOM from "react-dom"; import { QueryClient, QueryClientProvider, useQuery } from "react-query"; import { ReactQueryDevtools } from "react-query/devtools"; const queryClient = new QueryClient(); export default function App() { return ( <QueryClientProvider client={queryClient}> <Example /> </QueryClientProvider> ); } function Example() { const { isLoading, error, data, isFetching } = useQuery("repoData", () => fetch( "https://api.github.com/repos/tannerlinsley/react-query" ).then((res) => res.json()) ); if (isLoading) return "Loading..."; if (error) return "An error has occurred: " + error.message; return ( <div> <h1>{data.name}</h1> <p>{data.description}</p> <strong>???? {data.subscribers_count}</strong>{" "} <strong>✨ {data.stargazers_count}</strong>{" "} <strong>???? {data.forks_count}</strong> <div>{isFetching ? "Updating..." : ""}</div> <ReactQueryDevtools initialIsOpen /> </div> ); } const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);复制代码
这个例子很好地体现出了我们对一个请求最关心的三个部分:返回值、错误和请求loading。react query并不替你发送请求,它做的是对请求的管理。
核心api
useQuery
当需要查询数据的时候使用useQuery
语法
const result = useQuery({ queryKey, queryFn, enabled, })复制代码
参数说明
const [page, setPage] = useState<{ current: number; pageSize: number; }>({ current: 1, pageSize: 10 }); const [params, setParams] = useState<{ name: string; status: number }>(); const { data, isLoading, refetch } = useQuery( ['files', page, params], () => { return fetch({ url: '/api/files', method: 'POST', body: { page, params }, }); }, { onSuccess(data) { console.log(data); }, }, );复制代码
这段代码里,在page和params变化的时候会自动进行请求,因此不需要额外用户操作后再次发起请求更新数据。 但是默认情况下,第一次进来也会进行一次请求,另外如果请求失败,会进行三次重试。这是react-query默认设置的。
queryKey
必传
用于此查询的query key。
当此键更改时,查询将自动更新(只要
enabled
未设置为false
)。queryFn:(context: QueryFunctionContext) => Promise<TData>
在没有指定默认的query function时必传
可以从context中获取
queryKey
必须返回一个promise
第三个参数可以传一个对象,其中几个常用的属性如下:
enabled: 可以关闭自动更新
retry: 请求失败重试,可以关闭或传入重试次数
onSuccess: 成功回调
onError:失败回调
refetchOnWindowFocus: 如果数据过期了,当window focus时会进行请求(这也是默认设置),可以关闭该特性
staleTime:多长时间数据会过期
QueryClient
以上选型可以通过QueryClient设置默认值:
const queryClient = new QueryClient(); // 默认不在挂载和focus时自动运行,不重试,但是默认enable为true,根据依赖变化自动运行 queryClient.setDefaultOptions({ queries: { refetchOnWindowFocus: false, refetchOnMount: false, refetchOnReconnect: false, retry: false, }, });复制代码
useMutation
当需要变更数据时使用useMutation
const Upload: FC<UploadProps> = function (props) { const component = props.dragger ? FileSelector.Dragger : FileSelector; const { mutate, isLoading } = useMutation( (file: File) => { const formData = new FormData(); formData.append('file', file); formData.append('name', file.name); return fetch({ url: '/api/upload', method: 'POST', body: formData }); }, { onSuccess(data) { message.success('文件上传成功'); props.onSuccess?.(data); }, onError(err) { message.error('文件上传失败'); props.onError?.(err); }, }, ); const upload = (f: RcCustomRequestOptions) => { mutate(f.file); }; return React.createElement( component, { customRequest: upload, ...props }, props.children || props.dragger ? ( <p className="p-6">点击或拖拽文件到此区域</p> ) : ( <Button type="primary" htmlType="button" loading={isLoading} disabled={isLoading} > <Icon type={props.icon || 'upload'} className="align-middle" /> <span className="align-middle"> {props.text || '上传文件'}</span> </Button> ), ); };复制代码
上面这段代码是一个简单的上传组件:
用户点击按钮
选择文件
发起请求
这里的请求需要我们主动发起,这时候就需要调用useMutation
返回的mutate
参数
const { data, error, isError, isIdle, isLoading, isPaused, isSuccess, mutate, mutateAsync, reset, status, } = useMutation(mutationFn, { mutationKey, onError, onMutate, onSettled, onSuccess, useErrorBoundary, }) mutate(variables, { onError, onSettled, onSuccess, })复制代码
mutationFn: (variables: TVariables) => Promise<TData>
必传
一个返回promise的函数。
参数
variables
由mutate
传过来onSuccess: (data: TData, variables: TVariables, context?: TContext) => Promise<unknown> | void
可选
成功回调
onError: (err: TError, variables: TVariables, context?: TContext) => Promise<unknown> | void
可选的
失败回调
retry: boolean | number | (failureCount: number, error: TError) => boolean
如果设置为
false
,失败后不会重试。
作者:布列瑟农的星空
链接:https://juejin.cn/post/7028165657954910222