Skip to content

子组件数据刷新问题

问题描述: 父组件在 v-for 中使用子组件,子组件有两个业务功能,分别是发起报检和取消报检;业务需求是调用上述两个功能后,子组件的数据能够重新刷新。分别在子组件的两个业务方法中通过 this.$emit('refresh') 调用了父组件的数据刷新方法,但是子组件的数据并没有正确的重新刷新

问题分析

v-for 遍历的是 tables 数组变量,数据未成功刷新的原因可能是 tables 数组的引用没有改变,导致 Vue 无法检测到数据变化

解决方案

  1. 修改父组件的 refresh 方法,确保每次都会创建一个新的数组引用:接口返回数据后,使用展开运算符创建新数组,确保引用改变
    this.tables = [...(resultData.length > 0 ? resultData : [{}])];
    
  2. 在子组件中,添加 watch 监听 props 中的数据变化,并调用子组件中的数据初始化方法:
    watch: {
        initComponentData: {
            handler(newVal) {
                if (newVal) {
                    this.initData(newVal);
                }
            },
            deep: true,
            immediate: true
        }
    }
    
  3. 在父组件中,修改模板以添加 key 属性,强制 Vue 重新创建组件:
    <inspection-table
        @cell-edit="handleCellEdit"
        @refresh="initData"
        v-for="(item, index) in tables"
        :key="'table-' + index + '-' + (item.updateKey || 0)"  // 添加updateKey
        :ref="`InspectionTable${index}`"
        :initComponentData="item"
        :disabled="false"
        :parameter-value="parameterValue"
        :indexItem="index"
    ></inspection-table>
    
  4. 父组件初始化数据时,为每个表格项添加时间戳作为更新标识:
    initData() {
        const data = {
            expId: this.parameterValue.expId,
            projectId: this.parameterValue.projectId
        };
        InspectionShowList(data).then(res => {
            if (res.code === 200) {
            const resultData = res.result || [];
            // 添加时间戳作为更新标识
            const timestamp = new Date().getTime();
            this.tables = resultData.length > 0 ? 
                resultData.map(item => ({...item, updateKey: timestamp})) : 
                [{ updateKey: timestamp }];
            this.allComponentData = resultData.length > 0 ? 
                resultData.map(item => item.data) : [];
            }
        }).catch(error => {
            this.$message.error('获取数据失败:' + error.message);
        });
    }
    

总结

  1. 强制组件重新渲染:通过修改 v-forkey 属性,确保每次数据更新时 Vue 都会重新创建组件实例。
  2. 深度监听数据变化:使用 watch 监听 父组件传递的 propsinitComponentData 的深度变化,确保数据更新时能正确响应。
  3. 保持数据响应式:使用展开运算符 ... 创建新数组,确保 Vue 能检测到数据变化。
  4. 添加更新标识:使用时间戳作为 updateKey,确保每次数据更新时 Key 都会改变。
  5. 清理旧数据,在重新初始化数据前,先清空现有数据,避免数据残留。