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

Vue3引入子组件后beforeMount无限执行问题求助

Vue3 组件引入后无限执行及报错问题排查

问题现象

  • 未引入子组件时,beforeMount钩子仅执行一次,页面正常显示
  • 引入子组件后,代码开始无限循环执行,Node控制台重复打印SQL查询日志
  • 移除子组件中的动态变量(如{{ clientArray.clientPhone }})后恢复正常
  • Chrome控制台报错:Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'length'),对应代码行184:
<tbody v-if="vehicleData && vehicleData.vehicleTask.length">
  <tr v-for="Task, index in vehicleData.vehicleTask" :key="Task.id">
    <th scope="row" colspan="2">{{ index }}</th>
    <td colspan="2">{{ Task.title }}</td>
  </tr>
</tbody>

涉及代码

父组件

<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable">
    <div class="modal-content">
      <div class="modal-header">
        <h1 class="modal-title fs-5" id="exampleModalLabel">预查看工单</h1>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="关闭"></button>
      </div>
      <div class="modal-body">
        <DevizView :clientArray="clientData" :vehicleArray="vehicleData"/><!-- 子组件 -->
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
        <button type="button" class="btn btn-primary">保存更改</button>
      </div>
    </div>
  </div>
</div>

<script>
import axios from "@/axios";
import DevizView from "@/views/Test.vue";

export default {
  props: {
    id: {
      type: Number,
      required: true,
    },
  },
  data() {
    return {
      vehicleData: [],
      clientData: []
    }
  },
  components: {
    DevizView
  },
  methods: {
    async GetVehicleDetails() {
      await axios.post('http://localhost:3000/vehicle/GetVehicleDetails', {id:this.id})
        .then((res)=>{
          this.vehicleData = res.data;
          // 将字符串化的JSON解析为真实对象
          try {
            this.vehicleData.vehicleTask = JSON.parse(this.vehicleData.vehicleTask);
          } catch (error) {
            console.error('解析vehicleTask JSON失败:', error);
          }
        }).catch(err=>console.log(err))
      return this.vehicleData
    },
    async GetCustomerDetails() {
      await axios.post('http://localhost:3000/customer/GetCustomerDetails', {id:this.vehicleData.clientId})
        .then((res)=>{
          this.clientData = res.data;
        }).catch(err=>console.log(err))
      return this.clientData
    },
  },
  beforeMount(){
    this.GetVehicleDetails().then(() => {
      this.GetCustomerDetails();
    });
  }
};
</script>

子组件

<div class="table-responsive">
  <table class="table table-sm caption-top">
    <caption><strong>客户/车辆信息</strong></caption>
    <tbody>
      <tr>
        <th class="table-secondary">姓名</th>
        <td colspan="3">{{ clientArray.clientName }}</td>
      </tr>
      <tr>
        <th class="table-secondary">电话</th>
        <td>{{ clientArray.clientPhone }}</td>
        <th class="table-secondary">邮箱</th>
        <td>{{ clientArray.clientEmail }}</td>
      </tr>
      <tr>
        <th class="table-secondary">入库日期:</th>
        <td>{{ vehicleArray.vehicleEnterDate }}</td>
        <th class="table-secondary">出库日期:</th>
        <td></td>
      </tr>
    </tbody>
  </table>
</div>

问题原因及解决方案

1. 初始值类型不匹配

父组件中vehicleData和clientData初始值设为数组[],但接口返回的是对象。子组件渲染时访问对象属性,初始数组无对应属性会触发警告,引发不必要的重渲染。

  • 修复:将初始值改为空对象{}:
data() {
  return {
    vehicleData: {},
    clientData: {}
  }
}

2. 异步加载期间的空值访问

接口返回前子组件已开始渲染,vehicleData.vehicleTask可能为undefined,读取length时报错。报错触发组件重渲染,进而重复调用接口,形成无限循环。

  • 修复:
    • 使用可选链操作符优化模板判断:v-if="vehicleData?.vehicleTask?.length"
    • 解析JSON时设置默认值,避免vehicleTask为undefined:
      try {
        this.vehicleData.vehicleTask = JSON.parse(this.vehicleData.vehicleTask) || [];
      } catch (error) {
        console.error('解析vehicleTask JSON失败:', error);
        this.vehicleData.vehicleTask = []; // 解析失败时设为空数组
      }
      

3. 子组件未声明Props

子组件直接使用clientArray和vehicleArray但未声明Props,Vue会将其视为隐式属性,导致重渲染逻辑异常。

  • 修复:子组件添加Props声明:
<script>
export default {
  props: {
    clientArray: {
      type: Object,
      default: () => ({})
    },
    vehicleArray: {
      type: Object,
      default: () => ({})
    }
  }
}
</script>

4. 异步流程简化

将beforeMount中的嵌套异步调用改为async/await写法,提升可读性:

async beforeMount() {
  await this.GetVehicleDetails();
  await this.GetCustomerDetails();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 06:32:32