报错背景
在使用Vue组件化开发程序的时候,会遇到下面这样的报错信息;
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value.
怎么造成的?
这个错误是由于直接修改了从父组件传递过来的prop值导致的;
错误代码
首先来看一下我自定义的某个子组件,里面有三个不同数据类型的prop。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export default {
props: {
movies: Array,
user: Object,
searchQuery: String,
},
methods: {
**sortMovies() {
this.movies = this.movies.sort();
},
search(query) {
this.searchQuery = query;
},
addToFavourites(movie) {
this.user.favourites.push(movie);
}
}**
}
上述里面三个方法sortMovies,search(),addToFavourites()都在直接修改prop。
我们很容易就这样去做,这是一个容易犯的错误,有时候你甚至不知道自己在去修改一个prop。
不过好消息是,VUE会给你发出报错信息。
说明
1)子组件中直接修改props是一种“反模式”。
在Vue中,我们使用props将数据向下传递组件树。父组件使用props来将数据向下传递给自己的子组件们,这些组件又将数据向下传递给下一层,以此类推。然后,我们使用events将数据在组件数中向上传递。
这样做可以确保每一个组件和组件相互间是独立的。所以我们可以确定:
- 只有组件自己可以改变自己的数据状态。
- 只有父组件可以改变这个props的值。
保持这些规则,可以让我们的组件更简单,更容易去追踪数据的流转。
但是如果我们直接修改props,我们就破坏了这个规则。
2)Vue重新渲染时会覆盖props
这是另一个需要记住的事情。
当Vue重新渲染你的组件的时候,它会覆盖你对props所作的所有更改。意味着即使你尝试在本地更改prop,Vue也会继续覆盖这些更改。
解决它
问题来了,很多情况下我们需要修改父组件传递过来的props。可能是对props中的数组重新排列,又或者是对props中的数值进行汇总或计算。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<ul>
<li v-for="item in list" />
</ul>
</template>
export default {
name: 'ReversedList',
props: {
list: {
type: Array,
required: true,
}
},
created() {
// Mutating the prop :(
this.list = this.list.reverse();
}
};
看上面代码,这是一个错误办法。
他只会反转父组件传递的初始list数组。如果父组件中的列表更新,那它就不会发生反转;
我们可以使用computed来解决。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
<ul>
<li v-for="item in reversedList" />
</ul>
</template>
export default {
name: 'ReversedList',
props: {
list: {
type: Array,
required: true,
}
},
computed: {
reversedList() {
return this.list.reverse();
}
}
};
上面代码中,我们设置一个计算属性reversedList。
reversedList在每次list更新时都会进行重新计算。