本文为 react-query 进阶高级技巧,适合对 react-query 已经熟练使用的人,关于 react-query 基础内容本文将不会再提,高阶读友可放心阅读。
假如你是零基础者,以下历史文章可供追溯:
《 React Api请求最佳实践react-query3使用教程(比swr更好用更强大)》
通过本文你可以对 react-query 形成一个初步认识,但接触面不会超过 50% ,在这之后你可以进行自己的学习精进到 80% 的认知。
《 Api请求库react-query之缓存出神入化——作为全局状态管理 》
通过本文你可以从另一个比较 hack 的角度了解 react-query,加深对 cache 的认知。
《 react-query在项目中的架构封装设计(大量实践经验)》
通过本文你可以进一步规范提升你的 RQ 编码技术,精进技巧,让代码封装的更加优美,提高可维护性和可拓展性。
我们这里要提的是,如何避免 react-query 的模板代码,快速把 RQ 接入?
从 《 react-query在项目中的架构封装设计(大量实践经验)》 一文中我们知道,RQ 进阶高级封装是需要很多模板代码的,繁杂紧迫的业务要求我们又要兼顾快速编码,又要高可维护,如何做到既要又要还要?
答案是 去其槽粕,取其精华 。
我们把使用分为两类,一类是 查询( useQuery
),一类是请求( useMutation
)。
先看一个 查询( useQuery
) 的 case。
接口层:
export interface IGetSearchResultParams {
key: any
}
export interface ISearchResult {
key: any
}
export const getSearchResult = async (params: IGetSearchResultParams) => {
const res = await getSearchSome(`//domain.com`, params)
return res?.data as ISearchResult | undefined
}
最需要注意的是你的 res?.data
可能为空!其他的我们不做多余说明。
RQ 层:
import { useQuery } from 'react-query'
import { isNil } from 'lodash'
import { IGetSearchResultParams, getSearchResult } from './path/to/api'
export const useSearchResult = (params?: Partial<IGetSearchResultParams>) => {
return useQuery(
['useSearchResult', params],
async () => {
const data = await getSearchResult(params as any)
// 你可能有一些其他固定逻辑在这里
// ...
return data
},
{
enabled: !isNil(params), // 更严格的 case:!isNil(params) && !isNil(params?.xxx)
}
)
}
来看一下我们设计的用心:
入参使用 Partial
作用原入参,得到 Partial<IGetSearchResultParams>
这样可以避免入参传递可能报空,否则你还要再引导一遍这个 type 或 as any
,因为多数情况瀑布流数据我们的入参实际上是有的,但是 ts 会报空,你完全没必要在这方面浪费时间精力。
RQ 的 key 方面,因为 RQ 天生支持对象,所以保证我们的 hooks 名互斥 + params 区分即可,也无需去抽离 key,加快业务编码速度。
最后最重要的安全性把控一定要做,保证数据流安全,最低限是做非 null
/ undefined
的处理,如果有其他重要参数,可多加判断。
实际上这个 RQ 的产出成本不到一分钟,由此以来 RQ 的模板成本便大幅减少!
对于 改删 类请求我的看法是比较开放的,hooks 可抽离也可不抽离,但是查询最好抽离,提供一个参考的 case :
const modifyMutation = useMutation(async (params: IUpdateDataParams) => {
const res = await updateDataApi(params)
if (res?.code === 0) {
message.success('成功')
// refetch data
someUseQuery.refetch()
// other success callback
// ...
return
}
message.error('失败,请重试')
})
// 下面你可以使用
const data = modifyMutation.data
const loading = modifyMutation.isLoading
再次回归本意,mutation 终究还是一个比较定制化的东西,你去抽离也无法改变有多处业务虽然是一个 api 但是入参不同的定制化逻辑,而且有时信息提示也不同,抽离的收益并不大,特别是复杂的定制业务。
RQ 在高级进阶后,我们尽量朝向减少模板代码的方向发展,我们要的是 RQ 帮我们管理状态的强大,和其具备的一些强大附属功能,但绝不能像 redux 一样给我们负收益了一大堆模板代码。