当我们尝试直接更改prop值时,Vue.js会显示警告,如下所示:
Vue.component('Games', {
template: `
<div>
<ol>
<li v-for="game in games">{{ game }}</li>
</ol>
<button @click="clear">Clear games</button>
</div>
`,
props: ['games'],
methods: {
clear: function () {
this.games = [];
}
}
});
显示的警告是:
避免直接更改prop,因为每当父组件重新渲染时,该值都会被覆盖。而是使用基于属性值的数据或计算属性。
我知道为什么会发生这种情况,但是令我惊讶的是.push()
不会发生这种情况。如果我更改了向数组添加值而不是重写值的方法,则不会发出警告:
methods: {
add: function () {
this.games.push('Whatever');
}
}
为什么没有警告?
如何直接推动道具罚款而不能重写?答案 0 :(得分:3)
这仅仅是因为Array
是一种参考内存。当您将Array
或Object
存储在任何变量中时,它就是参考变量。
Memory management
在这种情况下,引用变量将指向heap
中的内存地址,因此您可以在地址中添加更多n个值。但是,您不能仅用任何新值替换该地址,即使使用新地址也是如此。
答案 1 :(得分:1)
被推入的道具是一个数组。推送新值后,它仍然是数组。我相信vue不会对开箱即用的道具进行深入的监视(即,它并不关心数组中的内容)。
引用this文章;
const array = [1, 2, 3, 4]; // array = [1, 2, 3, 4] Now you update the array by pushing some more values into it: array.push(5); array.push(6); array.push(7); // array = [1, 2, 3, 4, 5, 6, 7]
这里的问题是:数组有变化吗?
好吧,这不是那么简单。
数组的内容已更改,但变量数组仍 指向相同的Array对象。数组容器没有改变, 但是数组内部发生了变化。
因此,当您观察数组或对象时,Vue不知道您已经 改变了道具里面的东西。您必须告诉Vue您想要它 在观察变化时检查道具内部。
Michael Thiessen的文章, 2018年10月发布-全部归功于他们。
针对您对此仍然是反模式的评论,我会这样说;
如果我们首先考虑为什么直接在组件上改变道具是一种反模式,那么推理仍然成立。再次引用迈克尔(我保证,我总是不小心绊倒他的东西);
“我们这样做是因为它确保每个组件都与 彼此。由此,我们可以保证一些可以帮助我们的事情 考虑我们的组件:只有组件可以更改自己的组件 州。只有组件的父项才能更改道具。”
答案 2 :(得分:1)
当组件被更新/渲染时,道具被作为值写入基础组件模型。这可以在“任何”时间再次发生。在v-if或v-for条件下渲染的组件通常会发生这种情况。在这种情况下,prop值再次从父级写入子级。
如果孩子增加了计数器,则只会增加道具的本地副本,原始值parent.data.counter
仍将保持值5。如果更新了父项(例如,通过设置{{1} }),然后Vue将使用来自父级的新值覆盖子级中的值。因此,孩子的所有更改都丢失了-这可能导致意外行为。
如果prop是一个数组,则内存中仅存在该数组的单个副本。数组的任何突变都将更改父级和子级中的原始数组。如果您愿意,这仅适用于数组本身的突变。尝试counter=counter-1
将会遇到与以前相同的问题。由于slice不会更改原始数组,而是创建一个副本,因此子级将与父级具有不同的引用,并且可能会表现出意外的行为。
child.propArray = child.propArray.slice(3)
Vue.component('child-comp', {
// camelCase in JavaScript
props: ['counter', 'arr'],
template: `<h3>Child Counter: {{ counter }} <button @click="inc">+</button>
-- Array: {{arr}} <button @click="push">push</button></h3></h3>`,
methods: { inc() { this.counter++ }, push() { this.arr.push(this.arr.length+1) } }
})
new Vue({
el: '#main',
data: { counter: 1, arr: [] },
methods: { inc() { this.counter++ }, push() { this.arr.push(this.arr.length+1) } }
})