疑惑:vue3使用props传递数据的时候,该属性是一个对象,实际情况下,到底推不推荐在子组件直接修改对象内部的属性?

假如父组件中是这样一个复杂的对象,传递给多个子组件,不同子组件要处理该修改中不同的属性,我目前的处理是直接在子组件中修改如props.params.approveStatus = 2,当然官方并不推荐这种处理,实际情况如何处理更好一些呢?

const params = ref<any>({
    approveStatus: 0,
    attachment: [],
    bidDeadline: '',
    bidFileValid: 0,
    bidId: null,
    bidMode: '',
    bidNo: '',
    bidScope: '',
    bidScopeAttachment: [],
    bidStage: 'initiate',
    bidTitle: '',
    buyMode: 1,
    contact: '',
    createBy: '',
    createTime: '',
    enterpriseId: 0,
    flag: 0,
    inquiryMethod: '',
    inquiryMethodAttachment: [],
    instanceId: 0,
    labelType: 0,
    promoterUserId: 0,
    promoterUserName: '',
    remark: '',
    requestionDeadline: '',
    sampleMode: 1,
    status: 0,
    supplierRecommenderId: null,
    supplierRecommenderName: '',
    technicalStandard: '',
    technicalStandardAttachment: [],
    updateBy: '',
    updateTime: '',
    valid: ''
  })
阅读 2.5k
avatarAI BotBETA

在 Vue.js 中,一般不推荐在子组件中直接修改 props。这是由于 Vue 的响应式原理决定的。当你将一个对象作为 prop 传递给子组件,并在子组件中修改这个对象的属性,父组件并不能感知到这个修改。这是因为 Vue 只会关注对象属性的 getter 和 setter,当你在子组件中直接修改对象的属性,getter 和 setter 并没有触发,所以 Vue 无法感知到这个修改。

那么,面对这种情况,我们应该如何处理呢?

一个常见的解决方案是,在子组件中不直接修改 props,而是通过触发一个事件将修改传递给父组件。在父组件中,你可以监听这个事件,并做出相应的处理。这种处理方式可以使你的组件间的数据流更加清晰,也更容易维护。

下面是一个示例:

子组件:

props: ['params'],
watch: {
  'params.approveStatus': function(newVal, oldVal) {
    this.$emit('update:params', { approveStatus: newVal });
  }
}

父组件:

<child-component :params="params" @update:params="updateParams"></child-component>

methods: {
  updateParams(newParams) {
    this.params = newParams;
  }
}

在这个示例中,子组件监听了 params.approveStatus 的改变,并在改变后触发了一个名为 update:params 的事件,将新的参数传递给父组件。父组件接收到这个事件后,更新了 params 对象。

对于你提到的复杂对象,你可以按照上述方式对需要修改的属性一一进行处理。这样虽然看起来可能有些繁琐,但是可以保证数据在组件间的流动是可控的,也有利于维护和调试。如果你需要处理大量的属性,你也可以考虑使用 Vuex 或者其它状态管理库来帮助你管理这些数据。

4 个回答

你这种多组件处理同一对象的情况,可以使用Pinia来做啊。

// 定义store
const useParamsStore = defineStore();

// 在每个组件里面直接使用
const params = useParamsStore()

正如官网所说的那样:

更改对象 / 数组类型的 props

当对象或数组作为 props 被传入时,虽然子组件无法更改 props 绑定,但仍然可以更改对象或数组内部的值。这是因为 JavaScript 的对象和数组是按引用传递,而对 Vue 来说,禁止这样的改动,虽然可能生效,但有很大的性能损耗,比较得不偿失。

这种更改的主要缺陷是它允许了子组件以某种不明显的方式影响父组件的状态,可能会使数据流在将来变得更难以理解。在最佳实践中,你应该尽可能避免这样的更改,除非父子组件在设计上本来就需要紧密耦合。在大多数场景下,子组件应该抛出一个事件来通知父组件做出改变。

官方也是说了,在最佳实践中应尽可能避免,但也要根据你的业务需求来决定。

我前不久有个跟你差不多的需求,列表里一个数据,进行比如停用/启用操作,我的子组件是专门服务于这种情况的,然后在调用接口成功后直接更改props.xxx.status里参数的状态,因为需求是需要无感刷新,且这种情况应该是属于父子组件紧密耦合的状态。

实际使用还是不推荐,
这样破坏了单向数据流 ,随着组件变得复杂,你传入的数据在什么时候被组件内部改变了,你都不知道,可能导致一些难以发现的bug.
当你要在组件内部更改时,建议用emit到组件外部更改

const emit = defineEmits(['update:params'])
emit('update:params',val)
<template>
    <A v-model:params="params"></A>
</template>

渲染框架都推荐单向数据流,目的是比较好追踪数据的改动

处理就是父组件封装接口修改数据,然后父组件进行自定义事件监听,子组件需要修改数据的时候进行emit

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏