V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
17681880207
V2EX  ›  程序员

Vue3 hooks 的问题

  •  
  •   17681880207 · 2021-08-20 14:35:41 +08:00 · 2706 次点击
    这是一个创建于 1189 天前的主题,其中的信息可能已经有所发展或是发生改变。

    1 、因为很多页面都需要用到表格,所以我抽取了表格的逻辑到一个叫 useCommonTable.ts 的文件中,大概如下:

    // ...省略无关代码
    export default function (url) {
       const isLoading = ref(false)
       const tableData = ref([])
       const commonTableConfig = reactive({
         // ...
       })
       
       const getTableData = () => {
       	 // ...
       }
       
       return {
          isLoading,
          tableData,
          commonTableConfig,
          getTableData
       }
    }
    

    在使用的时候,一般就是如下:

    setup() {
      const {
        isLoading,
        tableData,
        commonTableConfig,
        getTableData
      } = useCommonTable('url')
      
      return {
        isLoading,
        tableData,
        commonTableConfig,
        getTableData
      }
    }
    

    但是好死不死,突然有一个页面有 2 个表格,然后逻辑也一样,那我解构就重名了

    setup() {
      // 表格 1
      const {
        isLoading,
        tableData,
        commonTableConfig,
        getTableData
      } = useCommonTable('url1')
      // 表格 2
      const {
        isLoading,
        tableData,
        commonTableConfig,
        getTableData
      } = useCommonTable('url2')
      
      return {
        isLoading,
        tableData,
        commonTableConfig,
        getTableData
      }
    }
    

    所以这种情况应该如何使用啊?我目前是

    setup() {
      // 表格 1
      const useTable1 = useCommonTable('url1')
      // 表格 2
      const useTable2= useCommonTable('url2')
      
      return {
        isLoading1: useTable1.isLoading,
        tableData1: useTable1.tableData,
        commonTableConfig :useTable1.commonTableConfig,
        getTableData1: useTable1.getTableData,
        isLoading2: useTable2.isLoading,
        tableData2: useTable2.tableData,
        commonTableConfig :useTable1.commonTableConfig,
        getTableData2: useTable2.getTableData
      }
    }
    

    感觉这种导入方式有点啰里八嗦的。。。不知道各位大神是如何做的?能否教教小弟。。。

    2 、关于 hooks 之间的调用

    // hook1.ts
    export default function() {
      const getStudentDetails = (studentId) => {
        // ...
      }
    }
    
    // hook2.ts
    export default function() {
      const getClassDetails = async () => {
         const studentIds = await self.$axios.get('...')
         // 这里希望调用 hook1.ts 中的方法
         // getStudentDetails(studentIds[0])
      }
    }
    

    如果使用 callback 方式,在 hook2.ts 中传入的话,会导致 setup 中的引入必须有先后关系:

    setup() {
      const {getStudentDetails} = useHook1()
      const {getClassDetails} = useHook2(getStudentDetails)
      
      return {
        // ...
      }
    }
    

    大哥们能教教小弟吗?新手勿喷,感谢大家!

    21 条回复    2021-08-21 11:44:57 +08:00
    gkinxin
        1
    gkinxin  
       2021-08-20 14:41:53 +08:00
    个人认为没有问题,结构重名其别名就行。
    silk
        2
    silk  
       2021-08-20 14:42:52 +08:00
    我觉得 loading 状态单独写 hook 然后 loading 状态跟表格绑定到一起是一个组件
    silk
        3
    silk  
       2021-08-20 14:45:07 +08:00
    还有你是写 hook 上瘾么 感觉没必要。vue 就老老实实 写流水账就行了
    17681880207
        4
    17681880207  
    OP
       2021-08-20 14:47:15 +08:00
    @silk 倒也不是上瘾,上面的问题只是我碰到问题之后的一个临时的一个 demo,想拿出来问问...
    sjhhjx0122
        5
    sjhhjx0122  
       2021-08-20 15:02:07 +08:00
    那 useCommonTable 应该封装到 table 组件去,每个页面都要写一次这个 hooks 其实也蛮多此一举的
    Danswerme
        6
    Danswerme  
       2021-08-20 15:07:06 +08:00
    问题 1 我也好奇怎么解决。问题 2 的话,我目前也用的 callback 方式。如果 setup 里用不到 useHook1 解构出来的其他部分,那就在 hook2.ts 中直接引入 hook1.ts ,setup 里也就不用引入了 hook1.ts 。

    前两天我也刚用 vue3 撸了一个瀑布流相册的 DEMO,里面就这么干的。


    https://github.com/vhvy/vue3-waterfall
    shilianmlxg
        7
    shilianmlxg  
       2021-08-20 16:06:48 +08:00
    @Danswerme 仰望大佬~~~~
    David1119
        8
    David1119  
       2021-08-20 16:16:34 +08:00
    这么啰嗦。。。哪位大佬仿照 react-query 撸个 vue-query ?
    John60676
        9
    John60676  
       2021-08-20 16:20:33 +08:00
    @David1119 这不巧了么
    vue-request ⚡️ 一个能轻松帮你管理请求状态(支持 SWR,轮询,错误重试,缓存,分页等)的 Vue 3 请求库
    仓库地址: https://github.com/AttoJS/vue-request
    shakukansp
        10
    shakukansp  
       2021-08-20 16:25:52 +08:00
    @sjhhjx0122
    这是 UI 组件和使用组件的逻辑的分离

    比如一个 table 可能有很多功能,一个页面可能用到其中几个,另一个页面用到另外几个,其中有几个是需要受控的,你不可能全部封装到组件内部,需要自由组合组件提供的 props 。然后这些组合还要可以复用,因为 A/B/C/D 页面需要用组合 A,E/D/F 需要组合 B,G/H 需要组合 C 。


    @David1119

    简单看着 swr 的 api 写了一个,vue2 vue3 的 vca 通用
    https://github.com/MinatoHikari/v-demi-request
    ccyu220
        11
    ccyu220  
       2021-08-20 16:44:33 +08:00
    上面的都说错了,这个是有解决方法的。
    当初我也封装了表格复用。
    具体方法,你在 hooks 里面定一个 register 方法,并用 getCurrentInstance 这个方法获取 uid 来做区分就好了。
    这样你同个页面有 10 个相同的表格都没关系。
    UnluckyNinja
        12
    UnluckyNinja  
       2021-08-20 17:23:38 +08:00 via Android
    第一个问题表示你该复用组件了……不复用都挤在父组件自然会遇到这个问题
    ccraohng
        13
    ccraohng  
       2021-08-20 17:27:39 +08:00
    全是模板代码。。。。
    antd 的 pro table 设计挺好的。

    这种 table 设计,不都是一个模式吗,抽成组件吧
    shakukansp
        14
    shakukansp  
       2021-08-20 17:48:09 +08:00
    @ccyu220 没看懂,两个组件放一个页面组件里那 getCurrentInstance 不都是同一个页面组件?

    楼主的前提肯定是组件要是受控的,在父组件用 props 控制
    suzic
        15
    suzic  
       2021-08-20 17:48:31 +08:00 via Android
    个人觉得没什么问题,解构的时候直接 cont {a: a1}=usexxx()就好了
    shakukansp
        16
    shakukansp  
       2021-08-20 17:52:11 +08:00   ❤️ 1
    问题 1 你可能可以试试 hooks 里面返回数组……,这样就不用映射重命名
    不过有一个问题是没提示了
    summerLast
        17
    summerLast  
       2021-08-20 17:53:28 +08:00
    @Danswerme 第一种是不是可以尝试直接封装一个 CommonTable 的组件呢 useCommonTable 在 CommonTable 中使用 <CommonTable :url="url" .../>
    summerLast
        18
    summerLast  
       2021-08-20 17:56:23 +08:00
    还有一种方式 就是不对 返回的数据展开 在使用的地方再展开
    summerLast
        19
    summerLast  
       2021-08-20 17:59:21 +08:00
    @shakukansp 这个其实就是抽象复用的问题 当相同的代码逻辑出现多次以后要不要抽象出来 什么时候抽象 组件也是如此
    shakukansp
        20
    shakukansp  
       2021-08-20 18:04:57 +08:00
    @summerLast hooks 就是为了少用高阶组件啊

    这么抽象又变成用很多 hoc 去复用了

    既然用 vca 了就把一些 props 也写进 hooks,然后复用的时候直接在原生组件用 v-bind 绑定所有需要的属性即可
    sjhhjx0122
        21
    sjhhjx0122  
       2021-08-21 11:44:57 +08:00
    @shakukansp 我的意思是他应该用这个 hook,封装一个基础 table 组件,复用这个组件,因为 loading,分页,请求都是基本功能,当封装的组件不满足他的基本需求时候,再用普通的 table 标签+hook 配合其他 hook,就像 ahooks 有 useAntdTable 的 hook,为什么 protable 还封装了这么多功能
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1170 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 18:28 · PVG 02:28 · LAX 10:28 · JFK 13:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.