V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
TWorldIsNButThis
V2EX  ›  前端开发

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

  •  
  •   TWorldIsNButThis · 2022-03-11 22:43:09 +08:00 · 2848 次点击
    这是一个创建于 1019 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

    9 条回复    2022-03-25 17:20:05 +08:00
    TWorldIsNButThis
        1
    TWorldIsNButThis  
    OP
       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
        2
    TWorldIsNButThis  
    OP
       2022-03-12 00:56:27 +08:00
    但是这样写第一次渲染的时候一定会请求两次 id ,有什么方法优化吗

    另外如果用 react query 实现相同的功能会不会简单些?
    HeStudy
        3
    HeStudy  
       2022-03-13 13:55:20 +08:00 via Android
    推荐 ahooks 里的 useRequest
    TWorldIsNButThis
        4
    TWorldIsNButThis  
    OP
       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
        5
    TWorldIsNButThis  
    OP
       2022-03-13 20:43:54 +08:00
    @HeStudy useRequest 的话是用 refreshDeps 解决吗 我再研究一下
    knives
        6
    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
        7
    TWorldIsNButThis  
    OP
       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
        8
    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
        9
    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}`);
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4691 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 09:54 · PVG 17:54 · LAX 01:54 · JFK 04:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.