react 的请求+缓存库 swr 的正确使用姿势? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
TWorldIsNButThis
V2EX    前端开发

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

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

    看了下很多人推荐用这个,但是官网文档也太简单了,而且也没有 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     Solana     939 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 22:07 PVG 06:07 LAX 15:07 JFK 18:07
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86