V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
iliaoliao
V2EX  ›  分享创造

[开源自荐] Quaere - 货拉拉内部的原子化服务端状态管理库.

  •  2
     
  •   iliaoliao ·
    liaoliao666 · 2023-09-20 10:12:58 +08:00 · 2775 次点击
    这是一个创建于 434 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Quaere 是什么

    "Quaere" 是一个 React 的原子化服务端状态管理库。

    Quaere 的核心实现来自于 Tanstack Query,但去除了 queryKey 概念,API 设计类似于 Jotai,提供了一套声明式的、原子化的状态管理方案,帮助你高效地管理服务端状态。

    动机

    Tanstack QuerySWR 在服务端状态管理上已经做得很不错,但仍然有下面的一些痛点。

    • 需要手动地管理你的 queryKey 和异步资源的对应关系。
    • 没有统一的地方管理,其 hook 很容易散落在项目各处。
    • 涉及到异步资源的操作时对 typescript 类型不友好。

    Quaere

    如果我既想受益于主流库,又没有这些痛点,怎么办呢?

    Quaere 就是为了解决这个问题而诞生的,它既包含了主流库特性也提供了一套声明式的、原子化的状态管理方案。

    快速开始

    下面是一个最基本的示例:

    import { query } from "quaere";
    
    const anQuery = query({
      fether: (variables) => axios.get(url, variables),
    });
    
    import { useQuery } from "quaere";
    
    function Example() {
      const { data } = useQuery({ query: anQuery, variables });
    }
    

    上面的示例展示了 Quaere 的两个核心函数:

    • query:用于创建一个异步资源解析配置,我们称其为 "查询配置"。

    • useQuery:该 hook 用于读取 "查询配置" 发起请求,并且每个不同 variables 都会返回与其相应的服务端状态。

    Typescript

    默认情况下,Quaere 会从 fetcher 推断出 类型,因此你可以自动获得首选类型。

    const todoQuery = query({
      fetcher: (variables: { id: number }) => {
        return { title: "todo" };
      },
    });
    
    // variables 将被推断为 { id: number }, data 将被推断为 { title: string }
    const { data } = useQuery({ query: todoQuery, variables: { id: 1 } });
    

    你还可以显式地指定 variablesdata 参数的类型。

    type Data = { title: string };
    type Variables = { id: number };
    
    const todoQuery = query<Data, Variables>({
      fetcher: (variables) => {
        return { title: "todo" };
      },
    });
    

    RealWorld Examples

    V2Fun 在网络体验方面完全受益于 Quaere 的各种特性,你可以从 V2Fun 源码中看到各种 Quaere 的真实世界使用案例。

    查看完整的文档和示例,请访问 quaere-site.vercel.app. 查看源码,请访问 quaere.

    9 条回复    2023-09-25 09:52:56 +08:00
    codehz
        1
    codehz  
       2023-09-20 10:19:26 +08:00
    怎么感觉这设计和某些 graphql 库很像🤔️
    iliaoliao
        2
    iliaoliao  
    OP
       2023-09-20 10:24:51 +08:00
    @codehz Apollo Client 和 GrahQL 也有参考一些。
    heyleo
        3
    heyleo  
       2023-09-20 11:53:43 +08:00
    没想到能在 v 站上面碰到同事。。赞一波,已 star
    iliaoliao
        4
    iliaoliao  
    OP
       2023-09-20 14:00:16 +08:00
    @heyleo 好兄弟
    shunia
        5
    shunia  
       2023-09-21 10:42:16 +08:00
    正常一个 fetcher 应该是这样:
    (title, id, content, authHeader | undifined) => <ResponseValueType>

    然后使用的时候正常应该像这样:
    use(query, [...requestParameters] | undefined, options | undifined)

    object 形式的入参的涵义就是可选的,虽然我知道 ts 可以很好的表达 object 中的可选值和必须值,但是还是觉得有点奇怪。
    我觉得可以参考 nodejs 的 api ,重新考虑一下方法入参的设计。

    省略两个常用库里的“key”的概念确实是比较大的卖点,支持一下。
    iliaoliao
        6
    iliaoliao  
    OP
       2023-09-21 11:29:21 +08:00
    @shunia 很专业,入参的设计考虑过像你建议的形式。但因为支持第一个参数为 query 的话会增加不少 typescript 代码,而且会与其他 API 产生割裂感,如 setQueryData 和 getQueryData 入参都是 { query, variables } 一般的 object 形式。但不排除以后会支持。

    至于 fetcher 是因为与请求库无关的,而其他 GraphQL 库的请求完全是由它们自身处理,自然它们能涵盖请求体的这些信息。
    qingyaun
        7
    qingyaun  
       2023-09-22 15:08:51 +08:00   ❤️ 1
    作者的 react-query-kit 也很不错👍
    pannanxu
        8
    pannanxu  
       2023-09-25 09:48:26 +08:00
    我的想法:集成 quaere-axios 、quaere-fetch 。然后使用的时候就可以直接采用
    ```js
    const anQuery = query(url);
    ```
    解放我的双手
    iliaoliao
        9
    iliaoliao  
    OP
       2023-09-25 09:52:56 +08:00
    @pannanxu 简单写个高阶函数就可以了,没啥必要单独写个库
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3270 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 12:25 · PVG 20:25 · LAX 04:25 · JFK 07:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.