ahooks useTable - 查询表格场景插件化 Hook 解决方案 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
monkindey
V2EX    前端开发

ahooks useTable - 查询表格场景插件化 Hook 解决方案

  •  
  •   monkindey
    monkindey 2020-08-26 10:00:23 +08:00 1807 次点击
    这是一个创建于 1876 天前的主题,其中的信息可能已经有所发展或是发生改变。

    为什么要有 useTable ?


    在中后台场景中,查询表格的场景占比较高。你会发现该场景写起代码会充斥着重复性的代码,比如点击下一页的时候,你需要把表单查询条件带过去,点击查询的时候你需要把页码归为 1 等常规逻辑。当然还有很多增强功能,比如排序、filter 、多选功能。

    我们面临“高效”和“灵活”权衡问题,高效的话可以一个组件来实现上面功能然后通过 props 来配置,这样子可能会减少了灵活性,灵活又可能需要使用方手写很多代码才能完成一个功能,失去了高效性。

    最后借鉴了 Egg 和 Babel 的思想,通过 Core + Plugin 的方式来平衡“高效”和“灵活”。同时设计的过程中,我们减少新概念出现,尽量使用业界通用的方案来减少学习成本。我们花费大量时间去思考插件设计,并且数字供应链已经做第一个吃螃蟹的人,基本上所有的查询表格场景都用这个方案了。现在是时间放出来让大家 Review 下了,期望有更多场景的输入,这样子 useTable 才能做得更好。

    useTable 是什么?


    useTable 针对的是查询表格场景的一些状态逻辑处理,比如请求的时候有 loading,请求成功之后设置 dataSource,点击下一页的时候请求等。本身不关心 View 层,并不是重新造一个 Table 组件。

    它包含以下特性:

    • 可扩展:可定制能力强,插件易开发,方便与 Fusion 、Antd 等 Design 系统集成
    • 开箱即用:提供多个场景的插件,方便快速支持不同场景的需求
    • Hooks:全部基于 Hook 实现,拥抱 React 新特性,减少学习成本


    整体概览:

    image.png

    最底层 useTable 具备插件能力,可以通过插件生成具备插件能力的 Hook,可以一直套娃下去,然后适配不同 Design 系统。上层建设可以多种多样,底层可以共用一套插件技术体系。

    基于前面所遇到的场景和思考,我们发布了 ahooksjs useTable v0.1.0 版本让大家可以尝鲜。

    useTable 具备了什么能力?


    useTable 提供核心 useTable & useFormTable 规范,还有对应 next 版本的 useNextTable & useNextFormTable,方便使用 Fusion Next 的开发者快速使用,后续也会支持 Antd,还提供官方多个场景插件。下面一一介绍下:

    • @ahooksjs/use-table:核心底层具备插件能力的 useTable 规范
    • @ahooksjs/use-form-table:核心底层具备插件能力的 useFormTable 规范
    • @ahooksjs/next-table:底层 useTable 的 next 版本
    • @ahooksjs/next-form-table:底层 useFormTable 的 next 版本
    • @ahooksjs/use-selection-plugin:多选插件
    • @ahooksjs/use-sortable-plugin:排序插件
    • @ahooksjs/use-filter-plugin:过滤插件
    • @ahooksjs/use-tree-plugin:懒加载树插件
    • @ahooksjs/use-async-default-plugin:异步默认值插件

    那怎么使用呢?


    上面说了这么多,是时候看看真面目了,是骡子是马拉出来遛遛。下面主要是一些伪代码,主要为了简单描述下如何使用,更多可以看官网的快速开始

    简单版


    useNextFormTable 会返回不同组件的 Props,然后可以赋给对应的组件,useNextFormTable 帮你管理状态逻辑,现在看起来并没有什么特别之处。

    const CompOnent= () => { const { formProps, tableProps, paginationProps } = useNextFormTable(list); return ( <div> <SchemaForm {...formProps} compOnents={{ Input }} style={{ marginBottom: 20 }} inline> <Field name="name" title="name" x-compOnent={'Input'} /> <FormButtonGroup> <Submit>查询</Submit> <Reset>重置</Reset> </FormButtonGroup> </SchemaForm> <Table {...tableProps}> <Table.Column title="name" dataIndex="name" width={200} /> </Table> <Pagination style={{ marginTop: 16 }} {...paginationProps} /> </div> ); }; 


    上面只是完成一个最 Basic 的能力,那如果需要加上其他功能比如多选,我们如何实现呢?我们提供的方案是 useNextFormTable 具备扩展能力,然后根据场景沉淀出不同插件,并且这些插件可以同时使用。具体可以看下下面的例子是如何使用的?

    插件版


    加上多选的功能,多选的插件已经帮你完成下面的功能了

    • 设置 Table props,比如 rowSelection ;
    • 监听事件,比如 onSelect ;
    • 重新查询之后要清除选中项;
    import "@alifd/next/dist/next.css"; import React from "react"; import useNextFormTable from "@ahooksjs/next-form-table"; import useSelectionPlugin from "@ahooksjs/use-selection-plugin" import { Table, Pagination } from "@alifd/next"; import { SchemaForm, Field, Submit, Reset, FormButtonGroup } from "@formily/next"; import { Input } from "@formily/next-components"; export default function App() { const plugin = useSelectionPlugin() const { formProps, tableProps, paginationProps } = useNextFormTable(list, { plugins: [plugin] }); return ( <div style={{ padding: 20 }}> <SchemaForm {...formProps} compOnents={{ Input }} style={{ marginBottom: 20 }} inline > <Field name="name" title="name" x-compOnent={"Input"} /> <FormButtonGroup> <Submit>查询</Submit> <Reset>重置</Reset> </FormButtonGroup> </SchemaForm> <Table {...tableProps}> <Table.Column title="name" dataIndex="name" width={200} /> </Table> <Pagination style={{ marginTop: 16 }} {...paginationProps} /> </div> ); } 


    基本上你只需要引入多选插件,然后直接使用它就可以完成多选功能,而不需要在各个地方写逻辑。当然多插件一起使用也是支持的,文档上有对应的例子

    如何定制?


    如果官方插件不能满足你的要求的,你完全可以自定义自己的插件,还有如果你部门也有自己的 Design 系统,组件的 props 定义不一样,可以看文档的『插件开发』和『结合 Design』,帮助你快速定制符合你具备插件化能力的查询表格。

    上层建设


    上层建设可以多种多样,你可以用源码开发,也可以通过数据驱动,还可以通过配置化的方式,底层共用同一套插件体系。useTable 不关心上层建设,只是提供方便上层建设的能力。

    需要你


    ahooks useTable 现在还是很年轻,需要更多场景的输入才能越做越好。大家们有任何问题或者建议都可以提到 Github Issue 上,我们会第一时间处理。

    5 条回复    2020-08-26 11:45:23 +08:00
    otakustay
        1
    otakustay  
       2020-08-26 10:16:00 +08:00   2
    我认为在 hook 上这么玩 plugin 的方案非常扯谈,hook 本来就是一套函数式的设计,基于原子的数据来增强就好
    const tableProps = useTable(list);
    const propsWithSelection = useSelection(tableProps);
    const propsWithSort = useSort(propsWithSelection);

    这样甚至可以很快速地构建出适合自己的 hook:
    const useOwnTable = compose(useTable, useSelection, useSort);

    任何一个东西,加上插件就是在增加概念,插件不是一个公认的逻辑,每一个插件系统的实现和设计都是不一样的,让人去理解成本并不低
    monkindey
        2
    monkindey  
    OP
       2020-08-26 10:37:35 +08:00
    @otakustay plugin 其实就是一个 hook,只是一个高级 hook,返回对应的属性而已。而且多选、排序都是依赖查询流程的,如果你只是关心 props 的话,没办法一下就完成一个功能,比如多选勾选的时候,重新点击查询会清空掉勾选的值,排序也是一样的情况。

    其实 useTable 是具备插件合并的能力,每一个插件也是一个 hook,你可以理解 useTable 就是一个 compose,useTable 、useSelction 、useSort 是一个插件。也就是你的理解:

    const useOwnTable = compose(useTable, useSelection, useSort);

    相当于

    const useOwnTable = useTable(useSelection, useSort)
    monkindey
        3
    monkindey  
    OP
       2020-08-26 10:44:48 +08:00
    @otakustay 插件你可以理解是增加一个概念,但是里面用的东西都不是新概念,都是一些业界流行的概念合并在一起。因为我们要写一个地方就可以解决一个功能的,不需要我加一个多选的功能或者排序的功能都要用 useState 状态管理,然后设置 props,然后在请求的链路中还要去清除勾选项,你会发现代码写起来就很繁琐,特别是当你负责很多类似页面的时候。
    otakustay
        4
    otakustay  
       2020-08-26 11:16:23 +08:00
    > 而且多选、排序都是依赖查询流程的,如果你只是关心 props 的话,没办法一下就完成一个功能

    我会选择先弄一个 useTableParams 的东西来组装参数,useTableXxxParams 追加参数

    算是设计理念上的不同吧,我比较喜欢“如无必要,勿增概念”的玩法
    monkindey
        5
    monkindey  
    OP
       2020-08-26 11:45:23 +08:00
    @otakustay 额额,同意你的设计理念,我也喜欢简单。我也思考很久,说服很多人,整一个设计并没有加概念,插件其实一个 hook,里面有 middleware 还有 compose 都是业界通用方案,只是在这里把它们合在一起。

    组装参数只是一部分,还有在查询前做事情,在查询后做事情,比如我们这边有人实现一个服务端驱动的插件,还可以拦截 response 做格式化。

    因为我不知道你们有没有做过中台页面,可能代入感比较弱。你提的问题我们这边在对这个方案的时候也提出来过,但是最后都认同了。如果你想进一步交流的话,可以加我微信 atob('bW9ua2luZGV5') ( console 执行下 )
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5772 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 36ms UTC 03:10 PVG 11:10 LAX 20:10 JFK 23:10
    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