You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3渲染函数中提取组件变量后Template Ref返回null问题

Vue h函数中模板引用绑定失败的原因与解决方法

问题现象

将Vue单文件组件重构为h渲染函数时,遇到模板引用(Template Ref)的绑定问题:

  • 提前用h()创建组件VNode并赋值给变量,再在渲染函数的children中使用该变量,ref无法获取到组件实例,值为null
  • 直接在渲染函数的children中调用h()创建组件,ref能正常获取到组件实例

不符合预期的代码

import { h, defineComponent, reactive, ref, onMounted, defineExpose } from 'vue'
import { type PropType, type VNode } from 'vue'
import { Form, FormItem, Input, Button } from 'ant-design-vue'

export default defineComponent({
  // ...
  setup: (props: any, { expose }) => {
    const formRef = ref()

    onMounted(() => {
      console.log(formRef.value) // null
    })
    // 提前创建VNode并赋值给变量
    const form = h(
      Form,
      { ref: formRef, labelCol: formLabelCol, wrapperCol: formWrapperCol, model },
      formItems
    )
    return () =>
      h(
        'div',
        {
          style: {
            width: props.width ? props.width + 'px' : 'auto'
          }
        },
        [formTitle, form]
      )
  }
})

正常工作的代码

import { h, defineComponent, reactive, ref, onMounted, defineExpose } from 'vue'
import { type PropType, type VNode } from 'vue'
import { Form, FormItem, Input, Button } from 'ant-design-vue'

export default defineComponent({
  // ...
  setup: (props: any, { expose }) => {
    const formRef = ref()

    onMounted(() => {
      console.log(formRef.value) // 正常获取到form实例
    })
    return () =>
      h(
        'div',
        {
          style: {
            width: props.width ? props.width + 'px' : 'auto'
          }
        },
        [
          formTitle, 
          // 直接在渲染函数内创建VNode
          h(Form,
          { ref: formRef, labelCol: formLabelCol, wrapperCol: formWrapperCol, model },
          formItems)
        ]
      )
  }
})

原因分析

Vue的VNode是一次性的,且ref的绑定逻辑依赖于渲染函数的执行上下文:

  1. 提前在setup根作用域创建VNode,这个VNode只会被初始化一次,当渲染函数执行时,它已经脱离了当前的渲染上下文,无法正确完成ref的绑定流程
  2. 在渲染函数内部创建VNode,每次组件渲染时都会生成新的VNode,能正确参与到Vue的渲染生命周期中,ref绑定逻辑也能正常执行

解决方法

确保需要绑定ref的组件VNode是在渲染函数内部创建的,若要复用组件配置,可把配置参数单独提取出来,在渲染函数调用h时复用:

import { h, defineComponent, reactive, ref, onMounted, defineExpose } from 'vue'
import { type PropType, type VNode } from 'vue'
import { Form, FormItem, Input, Button } from 'ant-design-vue'

export default defineComponent({
  // ...
  setup: (props: any, { expose }) => {
    const formRef = ref()
    // 提前提取组件配置
    const formProps = { 
      ref: formRef, 
      labelCol: formLabelCol, 
      wrapperCol: formWrapperCol, 
      model 
    }

    onMounted(() => {
      console.log(formRef.value) // 正常获取实例
    })
    
    return () =>
      h(
        'div',
        {
          style: {
            width: props.width ? props.width + 'px' : 'auto'
          }
        },
        [
          formTitle, 
          // 渲染函数内创建VNode,复用配置
          h(Form, formProps, formItems)
        ]
      )
  }
})

内容的提问来源于stack exchange,提问作者eminoda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 21:28:36