Vuetify v3(2)- useRender
如果你需要使用 setup + jsx + 暴露组件内部属性
一般来说会在 render 函数里编写 jsx 代码并返回,在 setup 中返回需要用到的属性
下面例子中的 child.tsx 为了满足上面需求,setup 暴露(返回)了所有方法
如果我们需要将 child.tsx 中 reset,init 方法设为私有呢?
好像行不通,渲染函数只能拿到 setup 中返回的内容,此时会出现一个问题:
- 渲染函数需要的变量均需要在
setup中返回,导致无法控制组件暴露给外部的变量
你可能会想到 setup 中返回 jsx 渲染函数,并使用 expose 暴露需要暴露的东西
但是这个方法有一个问题,使用 expose 后组件实例中以 $ 开头的成员会被隐藏,导致很多高级的组件用法无法使用
例如如下代码:
1 | // test.tsx |
外部通过 <Test ref={testRef}></Test> 拿到组件实例 testRef,其内容如下
1 | const testRef = { testData: 233 }; // 组件上的 $el, $attrs 等等都拿不到了 |
那么有无两全其美的方法呢?
useRender 会给出答案
思路
调试 vue 源码亿下,找到 setup 的实现,跟踪到 handleSetupResult 方法,发现其逻辑如下:
1 | // handleSetupResult |
然后传递 vm 实例到方法 finishComponentSetup 中进行处理
1 | // finishComponentSetup |
最后会在 renderComponentRoot 方法中调用 instance.render 渲染组件
1 | // renderComponentRoot |
简单来说就是:
vm实例上有render就拿来用没有就找组件上的
render,组件上没有render就拿组件模板编译成render都没有那就渲染失败报错呗
到这里思路应该就很清晰了
如果我们在 setup 调用的过程中构建 render 并塞给当前 vm 实例,就可以实现在只暴露部分公开成员的同时,渲染函数能通过闭包拿到所有私有成员
实现
简单暴力,但有效
1 | import { getCurrentInstance } from 'vue'; |
从类型提示可以发现 render 并不是公开的,所以说该方法偏 Hook,说不准往后一次主版本号更新就寄了
不过既然 vuetify 这种知名项目都在使用该方法,就不用太担心了
使用
基于上面提到的 child.tsx 组件,为了方便对比源码我先贴下来
1 | import { defineComponent, ref } from 'vue'; |
我们将其改造成只暴露 title 成员
1 | import { defineComponent, ref } from 'vue'; |
此时父组件拿到的 Child 实例如下
1 | const childRef = { |
完美





