Vue3报Invalid vnode type when creating vnode警告问题排查
问题根源
报错来自非法的vnode类型,核心错误点有两个:
- 动态组件的 fallback 值非法
你在tableOrderComponent计算属性中,当showOrder为false时返回了空字符串''。Vue在渲染组件标签时,无法将空字符串识别为合法的组件/原生标签类型,因此抛出Invalid vnode type when creating vnode警告。
注意你虽然给组件加了v-show="showOrder",但v-show仅通过CSS的display属性控制元素显隐,组件在初始化阶段仍然会被创建,空字符串的组件类型会第一时间触发报错。 - 异步组件定义位置错误
defineAsyncComponent不应该放在computed内部执行,每次计算属性触发都会重新创建异步组件实例,会造成不必要的性能开销,也可能导致组件状态异常。
修复步骤
- 调整异步组件定义位置,移除错误的计算属性
将异步组件的定义提前到script顶层,删除原来返回空字符串的tableOrderComponent计算属性,同时优化重复调用pinia store的冗余代码:
<script setup> import {ref, defineAsyncComponent, reactive} from 'vue' import {useMainStore} from '@/store/main.js' import {useTableStore} from "@/store/tables"; import DefaultLayout from '@/layouts/DefaultLayout.vue' import { storeToRefs } from 'pinia' // 提前顶层定义异步组件,不要放在computed中重复创建 const TableOrderComponent = defineAsyncComponent(() => import("@/components/TableOrder.vue")) // pinia store单例只需调用一次,无需重复执行useTableStore const tableStore = useTableStore() const { userData } = useMainStore() tableStore.getTables() const { freeTables, usedTables, tables } = storeToRefs(tableStore) const loading = ref(false) const showOrder = ref(false) const props = reactive({ orderID: null, id: null, }) const tableOrder = (table) => { props.id = parseInt(table.id, 10) props.orderID = table.activeOrderID || null showOrder.value = true } </script>
- 调整模板渲染逻辑
不需要通过返回空字符串控制组件显隐,直接用v-if控制组件是否渲染即可,彻底避免非法vnode问题,同时给v-for补充key值优化虚拟DOM diff逻辑:
<template> <DefaultLayout> <template #default> <div class="row come-in"> <div class="card col"> <div class="card-header"> <span class="text-capitalize"> {{ userData.username }}</span> </div> <div class="card-body subheader"> Used Tables ({{ usedTables.length }}) </div> <ul class="list-group list-group-flush"> <li v-for="table in usedTables" :key="table.id"> {{ table.name }} </li> </ul> <div class="card-body subheader"> Free Tables ({{ freeTables.length }}) </div> <ul class="list-group list-group-flush"> <li v-for="table in freeTables" :key="table.id"> {{ table.name }} <a href="#" v-tooltip="'Add order to the table'" @click.prevent="tableOrder(table)"> <font-awesome-icon icon="fas fa-list-alt" /> </a> </li> </ul> </div> <div class="col"> <!-- showOrder为false时组件不渲染,从根源避免非法vnode类型问题 --> <TableOrderComponent v-if="showOrder" :orderID="props.orderID" :id="props.id" /> </div> </div> </template> </DefaultLayout> </template>
额外优化:给a标签的click事件增加
.prevent修饰符,避免点击时触发默认的页面跳转锚点行为。
内容的提问来源于stack exchange,提问作者Sasha
相关产品推荐
相关产品推荐

