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

Vue中reactive()导致checkRule函数递归执行的原因分析

Vue中reactive数组导致函数递归执行的原因?

问题描述

我的Vue应用里有个bug:在checkRule函数中,只执行绿色代码(注释掉errors.push("Testerror");及对应日志)时,console.log会准确执行两次(因有2个必填列存在空值),符合预期;但同时执行绿色与红色代码时,两个console.log会出现递归执行的情况。移除变量errors的reactive()修饰后,运行恢复正常。请问该现象是否与reactive()有关?原因是什么?

代码示例

<script setup>
import { reactive } from 'vue'

let errors = reactive([]);
  
const product_columns = [
    { name: "name", mandatory: true },
    { name: "brand", mandatory: false }
];
  
const products = [
  { id: 1, name: "Product1", brand: "TestBrand" },
  { id: 2, name: "", brand: "" },
  { id: 3, name: "Product3", brand: "TestBrand" },
  { id: 4, name: "", brand: "TestBrand" },
  { id: 5, name: "Product5", brand: "TestBrand" },
  { id: 6, name: "Product6", brand: "" },
  { id: 7, name: "Product7", brand: "TestBrand" },
];

function checkRule(name, value, index) {
  if (value == "") {
    // 如果是必填列
    if(product_columns.find(product => product.name === name).mandatory) {
      // 本应只在索引1和3的产品上打印(因为这两处name为空)
      console.log("Column " + name + " is mandatory on index: " + (index));
      
      errors.push("Testerror");
      console.log(errors);
      
      // 返回错误样式类
      return "bg-red-100"
    }
  }
  
}
</script>

<template>
  <div v-for="(product, index) in products" :key="product.id">
    <div :class="checkRule('name', product.name, index)">
      {{ product.name }}
    </div>
    <div :class="checkRule('brand', product.brand, index)">
      {{ product.brand }}
    </div>
    <br>
  </div>
</template>

问题解答

结论

这个现象完全和reactive()有关,核心原因是Vue的响应式更新机制触发了重复渲染,进而导致checkRule函数被反复调用。

具体原因

  • 响应式数组变更触发组件重渲染:当你调用errors.push("Testerror")时,errors是reactive创建的响应式数组,这个修改会被Vue检测到,立刻触发组件重新渲染。
  • 模板中的函数会在每次渲染时重新执行:模板里用:class="checkRule(...)"这种方式绑定函数,意味着组件每渲染一次,所有循环项的checkRule都会被重新调用一遍。
  • 形成无限渲染闭环:第一次渲染时checkRule执行,发现空值后修改errors触发重渲染;重渲染时所有checkRule再次执行,又会修改errors再次触发渲染,这个循环不断重复,就出现了日志递归打印的情况。
  • 移除reactive()恢复正常的原因:如果errors不是响应式的,errors.push不会触发Vue的响应式更新,组件只会初始渲染一次,checkRule也只会执行一次,自然不会出现重复调用的问题。

修复建议

  • 避免在模板属性绑定中直接调用会修改响应式状态的函数,这极易引发无限渲染。
  • 提前计算错误状态:比如在组件挂载时(onMounted)或者数据变化时(用watch监听products)批量校验,把结果存在变量中,模板直接使用预计算好的结果。
  • 调整校验时机:比如在提交表单、用户输入完成后再执行校验,而不是在组件渲染过程中做这件事。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 10:40:17