Vue3 - forwardRef

2,433 阅读1分钟

前言

如题,Vue 一直想要有 React 一样的 forwardRef 的功能。奈何官方并未提供该 API。当你写了一个抽象组件时,可以透传 attrseventsslots,就是无法透传 ref。不得不通过丑陋的this.$refs.xx.xx,并且在抽象组件内再写一个 computed,renturn this.$refs.xx。Vue3 已经彻底放弃 this 了。可以稍微短一点,但是还是无法让开发者忽略这个抽象组件,每当需要 ref 时,都得知道组件暴露的 ref 字段。

如何 forwardRef

// createHoc.js
import { h, getCurrentInstance, defineComponent } from 'vue'

function createInnerComp(
  comp,
  {
    vnode: { ref, props, children }
  }
) {
  const compVnode = h(comp, props, children)
  // ref 透传
  compVnode.ref = ref
  return compVnode
}

function forwradRefComp(comp) {
    const hoc = defineComponent({
      name: 'Hoc',
      /* 骗过上帝*/
      __asyncLoader: Promise.resolve(),
      setup() {
          const instance = getCurrentInstance()
          return () => {
            const vnode = createInnerComp(comp, instance)
            return vnode
          }
      }
    })
    return hoc
}
// ContentComp.vue
import { defineComponent, h } from 'vue'
import { forwradRefComp } from './createHoc'
const comp = defineComponent({
  name: 'ContentComp',
  setup (props, { expose }) {
    expose({
      a: 1
    })
    return () => {
      return h('div', null, 'ContentComp')
    }
  }
})

export default forwradRefComp(comp)

vue3 关键源码

由于 vue3 的 defineAsyncComponent API 本身就是一个抽象高阶组件,并且已经实现了我们想要的高阶组件创建方法,我们就是做了下 copy paste。

复制 createInnerComp 方法用来实现高阶组件。github.com/vuejs/core/…

setRef 时,通过 __asyncLoader 字段判断来跳过该组件 ref 的设置。我们在 render 里把 ref 字段赋值> 给我们想要透传的组件的 vnode 即可完成 forWardRef github.com/vuejs/core/…