【问题标题】:Vuejs editing prop object property in child componentVuejs在子组件中编辑道具对象属性
【发布时间】:2020-04-13 15:06:28
【问题描述】:

我使用 Vue 已经有一段时间了,但仍然没有清楚地了解与这个(可能有争议的)问题相关的好处。我知道有人以不同的方式多次询问过这个问题,但我找不到明确的答案。

作为“示例 1”,假设我有一个包含 address 对象的父组件,并将该地址传递给子 AddressForm,以便用户可以编辑它,如下所示:

// Parent.vue

<template>
    <AddressForm :address="address" @submit="onSubmit"/>
</template>

<script>
export default {
    data () {
        return {
            address: {}
        }
    },
    methods: {
        onSubmit() {
            console.log('Submit', this.address);
        }
    }
}
</script>

那么,子组件就长这样了,直接操作父地址对象的属性。 这里我只显示address.name 的输入以保持简洁,但您可以想象地址的任何其他属性也有类似的文本输入。

// AddressForm.vue

<template>
    <form @submit.prevent="onSubmit">
        <input v-model="address.name">
        <button type="submit">Submit</button>
    </form>
</template>

<script>
    export default {
        props: {
            address: {
                type: Object,
                required: true,
            }
        },
        methods: {
            this.$emit('submit');
        }
    }
</script>

这里的问题是我直接在孩子中编辑address 属性。当然,我没有收到 Vue 的任何警告,因为我只是在编辑 address 对象的属性,实际上并没有通过重新分配来改变它。

有无数的地方我可以读到为什么这不是最佳实践,它是一种反模式,而且是一个坏主意。您不应该更改子组件中的道具。

好的,但是为什么呢?有人可以提供任何类型的真实世界用例,上面的代码可能会导致问题发生吗?

当我读到做事的“正确”替代方法时,我更加困惑,因为我没有看到任何真正的区别。这就是我的意思:

我们称之为“示例 2”,我现在使用 v-model 来强制执行“正确”的 2 路绑定,而不是像示例 1 中那样直接编辑道具:

// Parent.vue

<template>
    <AddressForm v-model="address" @submit="onSubmit"/>
</template>

<script>
export default {
    data () {
        return {
            address: {}
        }
    },
    methods: {
        onSubmit() {
            console.log('Submit', this.address);
        }
    }
}
</script>
// AddressForm.vue

<template>
    <form @submit.prevent="onSubmit">
        <input v-model="localValue.name">
        <button type="submit">Submit</button>
    </form>
</template>

<script>
    export default {
        props: {
            value: {
                type: Object,
                required: true,
            }
        },
        computed: {
            localValue: {
                get: function() {
                    return this.value;
                }
                set: function(value) {
                    this.$emit('input', value);
                }
            }
        },
        methods: {
            this.$emit('submit');
        }
    }
</script>

示例 1 和示例 2 有什么区别?他们在做的事情,从字面上看,完全一样吗?

在示例 2 中,计算属性表示 localValue 始终等于 value。意思是,它们是同一个对象,就像在示例 1 中一样。

此外,当您输入输入时,如果您看到在 Vue 调试器中触发的事件,AddressForm 甚至不会发出 input 事件,大概是因为 localValue 实际上没有被设置,因为它是只是一个正在更改的对象属性。

这再次表明示例 1 和示例 2 正在做完全相同的事情。即使使用了v-model,对象属性仍会在子级中直接发生变化。

所以,我的问题是,为什么示例 1 被认为是不好的做法?示例 2 有何不同?

【问题讨论】:

    标签: vue.js


    【解决方案1】:

    参考docs,直接操作道具会导致几个问题:

    • 使应用的数据流更难理解
    • 每次父组件更新时,子组件中的所有道具都会刷新

    【讨论】:

      猜你喜欢
      • 2018-12-05
      • 2021-08-27
      • 2019-09-24
      • 1970-01-01
      • 2017-11-09
      • 2017-12-23
      • 2016-09-11
      • 2021-12-20
      • 2018-08-08
      相关资源
      最近更新 更多