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

Vue3父子组件响应式数组合并失败问题求助

问题排查与解决方案:Vue3响应式数组合并失败

错误原因

  1. concat方法使用错误:concat() 会返回新数组,不会修改原数组。父组件中直接调用 children.value.concat({ ...data }) 但未将返回值赋值给 children.value,原数组无任何变化。
  2. 子组件emit数据格式错误:子组件提交时用 { ...childrenArr.value } 将数组展开为对象(数组索引转为对象键),父组件接收的data并非数组类型,合并逻辑完全失效。
  3. 变量重名隐患:子组件内部定义的person与props传入的person重名,可能引发逻辑混淆(虽非当前问题直接原因,但需优化)。

修复步骤

1. 修正子组件emit的数据格式

子组件提交时直接传递原数组,无需展开为对象:

// Form.vue 中submit方法修改
function submit() {
  console.log('submit from FORM: ', childrenArr.value);
  emit('submit', childrenArr.value); // 直接传递数组,而非展开成对象
}

2. 修复父组件数组合并逻辑

选择以下两种方式之一更新响应式数组:

  • 方式一:push批量添加(修改原数组)
    适合需要保留原数组引用的场景:
// Home.vue 中submit方法修改
function submit(data) {
  children.value.push(...data); // 展开数组元素批量添加
}
  • 方式二:重新赋值数组(替换原数组)
    适合需要创建新数组的场景:
// Home.vue 中submit方法修改
function submit(data) {
  children.value = [...children.value, ...data]; // 合并后重新赋值
  // 或者用concat:children.value = children.value.concat(data);
}

3. 可选优化:避免变量重名

子组件内部的person变量与props重名,建议重命名:

// Form.vue 中修改内部person变量
const localPerson = reactive({
  name: 'person',
  age: 23,
});

修改后完整代码示例

Home.vue(父组件)

<script setup>
import Preview from './Preview.vue';
import Form from './Form.vue';

const person = reactive({
  name: 'John',
  age: 21,
});

const children = ref([]);

const currComponent = shallowRef(Form);

function submit(data) {
  // 方式一:push批量添加
  children.value.push(...data);
  // 方式二:合并后重新赋值
  // children.value = [...children.value, ...data];
}
</script>

<template>
  <KeepAlive>
    <component
      :is="currComponent"
      :person="person"
      :children="children"
      @submit="submit"
    ></component>
  </KeepAlive>
</template>

Form.vue(子组件)

<script setup>
const emit = defineEmits(['addChild', 'deleteChild', 'submit']);

const props = defineProps({
  person: {
    type: Object,
  },
  children: {
    type: Array,
  },
});

const childrenArr = ref([]);

// 重命名内部person避免重名
const localPerson = reactive({
  name: 'person',
  age: 23,
});

const child = reactive({
  name: 'child',
  age: 10,
});

const showForm = ref(false);

function submit() {
  console.log('submit from FORM: ', childrenArr.value);
  emit('submit', childrenArr.value); // 直接传递数组
}

function addChild() {
  if (childrenArr.value.length < 5) {
    showForm.value = true;
    childrenArr.value.push({
      name: child.name,
      age: child.age,
    });
  }
}
</script>

<template>
  <div>
    <button v-if="childrenArr.length < 5" @click="addChild" class="add-child">
      <svg
        width="24"
        height="24"
        viewBox="0 0 24 24"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
        class="btn-icon"
      >
        <g id="24px / plus">
          <path
            id="Union"
            fill-rule="evenodd"
            clip-rule="evenodd"
            d="M5.13332 10.8556C4.50125 10.8555 3.98887 11.3679 3.98887 12C3.98887 12.6321 4.50126 13.1445 5.13332 13.1445L10.8554 13.1445L10.8554 18.8668C10.8554 19.4989 11.3678 20.0113 11.9999 20.0113C12.632 20.0113 13.1444 19.4989 13.1444 18.8668L13.1443 13.1445L18.8667 13.1445C19.4988 13.1445 20.0112 12.6321 20.0112 12C20.0112 11.3679 19.4988 10.8556 18.8667 10.8556L13.1443 10.8556L13.1443 5.13338C13.1443 4.50132 12.632 3.98893 11.9999 3.98893C11.3678 3.98893 10.8554 4.50131 10.8554 5.13338L10.8554 10.8556L5.13332 10.8556Z"
            fill="#01A7FD"
          />
        </g>
      </svg>
      Add child
    </button>
  </div>
  <div v-if="showForm" v-for="(child, index) in childrenArr" :key="index" class="children-item">
    <div class="children-container">
      <form class="children-form">
        <div class="children-form-group">
          <ChildrenInput v-model="child.name" type="text" class="children-input" />
          <ChildrenLabel class="children-label">Name</ChildrenLabel>
        </div>
        <div class="children-form-group">
          <ChildrenInput v-model="child.age" type="text" class="children-input" />
          <ChildrenLabel class="children-label">Age</ChildrenLabel>
        </div>
      </form>
    </div>
  </div>
</template>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 17:46:01