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的绑定逻辑依赖于渲染函数的执行上下文:
- 提前在setup根作用域创建VNode,这个VNode只会被初始化一次,当渲染函数执行时,它已经脱离了当前的渲染上下文,无法正确完成ref的绑定流程
- 在渲染函数内部创建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
相关产品推荐
相关产品推荐

