react-query 应用

410 阅读2分钟

前言

       react-query 主要用于管理服务端的全局数据,与 redux 结合使用,可以区分管理客户端与服务端的状态,接下来的分享,会围绕 useQuery,useQueryClient,useMutation 等三个常用接口展开,演示缓存以及状态管理。

API

useQuery 用法如下:

useQuery<Project[]>(['peojects', parm], () => client('projects', { data: parm }))

useQuery 是reqct-query内置的hook,从函数签名上看,第一个参数是 queryKey,第二个参数是 Fn

(alias) useQuery<Project[], unknown, Project[]>(
queryKey: QueryKey, 
queryFn: QueryFunction<Project[]>, 
options?: UseQueryOptions<Project[], unknown, Project[]> | undefined
): UseQueryResult<...> (+2 overloads)

       queryKey 一般是 string类型,用于标识该数据对应的 Key,第二个参数是回调函数,主要用于获取异步数据。从用法上看,queryKey 也支持另外一种写法,既 [ ],这是 tuple 类型,'project'表示 Key,parm 则是作为缓存数据存在 react-query 中,同时 parm 更是作为一个依赖,用于监听内存刷新。

       在 useQuery 指定的内存后,可以通过 useQueryClient 来获取数据。useQueryClient 可以浅意的理解为管理中心,缓存数据的操作(增删改查)都是经由它触发,比如,获取内存数据以及刷新内存数据

const queryClient = useQueryClient() 
queryClient.getQueryData(queryKey)        // 内存数据
queryClient.invalidateQueries(queryKey)   // 刷新内存数据

       useMutation 是操作型 API,其实可以把它等同于多功能函数来看。useMutation 区分了同步逻辑和异步逻辑,直接集成了 success ,Error 的处理,查看函数签名,如下:

(alias) useMutation<any, any, Partial<Project>, { previousItems: unknown;}>
(mutationFn: MutationFunction<any, Partial<Project>>, 
options?: UseMutationOptions<any, any, Partial<...>,
{ previousItems: unknown;}> | undefined): 
UseMutationResult<...> (+3 overloads)

       第一个参数是 Fn,是用于异步逻辑处理,第二参数是 options,根据异步处理的结果进行回调。

useMutation 格式用法如下:

useMutation(
        (parm: Partial<Project>) => client(`projects/${parm.id}`, {
            method: 'PATCH',
            data: parm
        }),
        {
            onSuccess: () => {},  // 成功后回调,一般在这里设置内存
            async onMutate(targe: Partial<Project>) {
                // 同步逻辑
                return data;
            },
            onError(error:any,newItem:Partial<Project>,context:any) {
                // 错误处理
            }
        }
    )

范例代码

       范例场景为删除一笔数据,View 层代码如下:

     const { mutate:deleteProject} = useDeletProject(useProjectsQueryKey())
     const confirmDeletProject = (id:Number) => {
         Modal.confirm({
             title:'确定删除这个项目嘛?',
             content:'点击确定删除',
             okText:'确定',
             onOk(){
                deleteProject({id})
             }
         })
     }

 return <Dropdown overlay={
       <Menu>
           <Menu.Item onClick={()=> confirmDeletProject(project.id)} key={'delete'}>删除</Menu.Item>
       </Menu>
    }>
    </Dropdown>

useDeletProject 如下:

useMutation(
        ({id}:{id:Number}) => client(`projects/${id}`, { method: 'DELETE' }),
        onSuccess: () => queryClient.invalidateQueries(queryKey),
        async onMutate(targe: any) {
            const previousItems = queryClient.getQueryData(queryKey) 
            queryClient.setQueryData(queryKey, (old?: any[]) => {
                return callback(targe,old)
            })
            return { previousItems }
        },
        onError(error: any, newItem: any, context: any) {
            // error下不能刷新内粗,进行回滚
            queryClient.setQueryData(queryKey, context.previousItems)
        }
    )

使用心得

       从开发者角度看,useMutation 的设计并不算友好,因为开发人员偏向"同步编码",不管是 Promise, async/await 亦或是中间件(thunk,saga)等等,都在是尽力去规避回调地狱并让代码看上去是"同步运行"。useMutation 则是直白的区分了同步代码和异步代码的位置,这要求程序员需要将业务场景切割,分配到对应的代码位置,然后在 react-query 的语境中,再次重组。
       不过,react-query 面向服务端数据管理,将前端的数据管理又细化了,理念蛮新颖的,提供的缓存机制也属于前端优化,UI 体验有一个好的提升。