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

Vue组件搭配Vite HMR出现递归更新超限问题求助

问题:Vite HMR触发Vue递归更新警告

修改Vue3嵌套组件(如示例中的Child1.vue)并保存后,Vite HMR会持续重载该组件,最终触发Vue的Maximum recursive updates exceeded警告,控制台会输出大量重复日志及该错误提示。

代码示例

Child1.vue

<script setup lang="ts">
const emits = defineEmits(['list-change']);

emits('list-change', ['a', 'b', 'c']);

// 修改此处代码并保存即可复现问题
console.log('Child1.vue setup');
</script>

Child2.vue

<script setup lang="ts">
const props = defineProps<{
  list: string[];
}>();
</script>

App.vue

<template>
  <Child1 @list-change="handleListChange"></Child1>
  <Child2 :list="list"></Child2>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import Child1 from './components/Child1.vue';
import Child2 from './components/Child2.vue';

const list = ref<string[]>([]);
const handleListChange = (newList: string[]) => {
  list.value = newList;
};

console.log('App.vue setup');
</script>

问题原因

问题的核心在于Child1的setup函数中同步触发了父组件状态更新:

  1. 修改Child1并保存后,Vite HMR会重新加载该组件,执行其setup函数。
  2. setup中的emits('list-change')直接修改了父组件App的list状态。
  3. App的状态变更会触发依赖该状态的Child2重新渲染。
  4. Vue的响应式更新机制与Vite HMR的逻辑形成循环:Child1 HMR更新 → 触发父组件状态变更 → 组件树更新 → 再次触发Child1的HMR流程,最终超出Vue的递归更新限制,抛出警告。

解决方案

方案1:仅在组件首次挂载时触发emit

使用onMounted钩子,确保emit只在组件第一次挂载时执行,HMR更新时不会重复触发:

<script setup lang="ts">
import { onMounted } from 'vue';
const emits = defineEmits(['list-change']);

onMounted(() => {
  emits('list-change', ['a', 'b', 'c']);
});

console.log('Child1.vue setup');
</script>

方案2:利用HMR标记避免重复触发

通过Vite的HMR元数据标记,确保emit只执行一次:

<script setup lang="ts">
const emits = defineEmits(['list-change']);

// 仅在首次执行或非HMR环境下触发
if (!import.meta.hot || !import.meta.hot.data.hasEmitted) {
  emits('list-change', ['a', 'b', 'c']);
  import.meta.hot?.data.hasEmitted = true;
}

console.log('Child1.vue setup');
</script>

方案3:按需触发emit(绑定到特定场景)

如果emit是业务需求的一部分,将其绑定到用户操作或特定响应式状态变更,而非在setup中同步执行:

<script setup lang="ts">
import { ref } from 'vue';
const emits = defineEmits(['list-change']);
// 示例:绑定到按钮点击事件
const triggerChange = () => {
  emits('list-change', ['a', 'b', 'c']);
};
</script>

<template>
  <button @click="triggerChange">更新列表</button>
</template>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 08:15:03