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

Vue3报Invalid vnode type when creating vnode警告问题排查

问题根源

报错来自非法的vnode类型,核心错误点有两个:

  1. 动态组件的 fallback 值非法
    你在tableOrderComponent计算属性中,当showOrder为false时返回了空字符串''。Vue在渲染组件标签时,无法将空字符串识别为合法的组件/原生标签类型,因此抛出Invalid vnode type when creating vnode警告。
    注意你虽然给组件加了v-show="showOrder",但v-show仅通过CSS的display属性控制元素显隐,组件在初始化阶段仍然会被创建,空字符串的组件类型会第一时间触发报错。
  2. 异步组件定义位置错误
    defineAsyncComponent不应该放在computed内部执行,每次计算属性触发都会重新创建异步组件实例,会造成不必要的性能开销,也可能导致组件状态异常。
修复步骤
  1. 调整异步组件定义位置,移除错误的计算属性
    将异步组件的定义提前到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>
  1. 调整模板渲染逻辑
    不需要通过返回空字符串控制组件显隐,直接用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 00:03:20