react 的请求+缓存库 swr 的正确使用姿势?

2022-03-11 22:43:09 +08:00
 TWorldIsNButThis

看了下很多人推荐用这个,但是官网文档也太简单了,而且也没有 api 参考,比如那个 isvalidating ,官网一句话就没了,看了下示例,这个是指 mutate 以后加载的加载中状态吗?

另外还搜了下如果想实现根据 id list 拿数据,得手动实现一个接受 id list ,返回 promise 的 fetcher ?

那 id list 本身也是一个请求拿到的呢,如何实现先刷新 id list ,再刷新 id list 对应的数据?

另外 react query 看起来功能多不少,会不会更好用些?

2845 次点击
所在节点    前端开发
9 条回复
TWorldIsNButThis
2022-03-11 23:50:12 +08:00
const fetchId = async () => {
await new Promise((res) => setTimeout(res, 1000))
const millis = new Date().getMilliseconds().toString()
return millis
.substring(millis.length - 4)
.split('')
.map(Number)
}

const fetchData = async (ids: number[]) => {
await new Promise((res) => setTimeout(res, 1000))
return await Promise.all(ids.map((id) => new Promise((res) => res(`data-${id}`))))
}

const useData = () => {
const { data: ids, isValidating: updateId, mutate: mutateId } = useSwr('/api/ids', fetchId)
const {
data,
mutate: mutateData,
isValidating: updateData,
} = useSwr(ids && 'data', async () => {
return await fetchData((await mutateId()) || [])
})

return {
ids,
data,
mutateData,
mutateId,
updateData,
updateId,
}
}

好像找到一个解决方案,在 dependent query 里 mutate id ,根据返回的 id 再去请求,由于 swr 在短时间内多次调用只会发一次请求,所以最终也就发两次请求?但是不知道这算不算 anti-pattern ?
TWorldIsNButThis
2022-03-12 00:56:27 +08:00
但是这样写第一次渲染的时候一定会请求两次 id ,有什么方法优化吗

另外如果用 react query 实现相同的功能会不会简单些?
HeStudy
2022-03-13 13:55:20 +08:00
推荐 ahooks 里的 useRequest
TWorldIsNButThis
2022-03-13 18:55:31 +08:00
const useData = () => {
const {
data: ids,
isValidating: updateId,
mutate: mutateId,
} = useSwr('/api/ids', fetchId, {
onSuccess: async () => {
await mutateData()
},
})
const { data, mutate: mutateData, isValidating: updateData } = useSwr(() => ids, fetchData)

return {
ids,
data,
mutateData,
mutateId,
updateData,
updateId,
}
}

又换了个写法,现在请求次数就是 id 和 data 各一次了
感觉好像 dependent query 没必要保持 key 不变,但是在 id 的 onSucess 里刷新它的 dependent query 好像也有点怪。。
TWorldIsNButThis
2022-03-13 20:43:54 +08:00
@HeStudy useRequest 的话是用 refreshDeps 解决吗 我再研究一下
knives
2022-03-15 11:09:35 +08:00
个人感觉 swr 官网之所以简单,是因为 swr API 从概念上说就是这么简单 :doge ,至少个人觉得比 useRequest 反倒要清晰点(虽然从功能上不完全对等)。swr 的核心理念就是数据的无感知刷新加载,在 swr 看来,甚至 loading 状态都可以不需要强调。

回到你的问题:

1. isValidating 这个属性我个人的理解和你差不多。不过在实际中我从未用到这个属性……
2. 是这样。官方的推荐做法是 ['/api/xx', ids] 的形式,参考传入参数的章节。
3. 参考官方条件数据请求的章节。这种场景属于依赖请求的概念。

别的库,react-query 暂未实践过,之前用过 useRequest (非最新版本)。

useRequest 可能是为了保证项目中 API 的统一封装,引入了手动请求之类的 API ,反而把相关组件的生命周期搞复杂了不少。写起来感觉尚可但功能不稳定,之前遇到的问题就是不能按 key 实现全局的数据缓存。
TWorldIsNButThis
2022-03-15 19:02:02 +08:00
@knives dependent 官网也是一句话就没了,就说通过 getKey 的函数返回 falsy 值或者抛异常可以实现先获取 a 在获取 b ,但是完全没讲更新的事情

比如更新 id list 以后,id list 可能变可能不变,不变的情况下依然要更新 id 对应的 item ,这个是否是通过 onSuccess 手动触发 dependency 的更新?

想实现的效果是进来获取一次 id list 一次 item ,更新也是只请求一次 id list 和对应的 items
knives
2022-03-15 19:25:38 +08:00
没怎么看懂你的问题。

就你的例子来说,onSuccess 触发 ids 的 mutate 是没必要的。如果是以 useSwr(ids ? ['/api/foo', ids]: null) 形式的依赖调用,在 ids 有变化后这一调用也会被自动触发,不需要手工执行 mutate 。你现在的写法也不能说肯定有问题,但是不是官方建议的写法。

如果 ids 不变也需要触发 item 的更新……还不如直接 ids.concat([]) 触发 ids 变更算了。
xianyu191031
2022-03-25 17:20:05 +08:00
没看懂楼主的意思,useSwr 核心在于以 path(key)用作缓存,可以试试类似这种写法. id 变了后数据自动就变了
.
const getFetcher = (options) => (url) => { ... }

const useCustomSwr = (key, options) => {
return useSwr(key, getFetcher(options));
}

const { data: { ids } } = useCustomSwr(`api/id?id=${id}`);

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/839773

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX