I'm wondering if I'm doing this the best way possible; I've built a component which accepts a list of items as a prop, but then I need to mutate that list internally in the component, so I followed the VueJs docs to provide the prop value as a data property's initial value, and then using the data property when I need to make any changes to the data.
export default {
props: {
items: {
type: Array,
default: () => {
return []
}
}
},
data() {
return {
itemList: this.items
}
}
}
I noticed however that this causes the itemList
property to stick to the initial value, and won't update if the parent component provides a new items
value to this component, this makes sense as the component was already rendered and thus it doesn't need to reevaluate all it's data
properties; so to fix this I added a watcher to watch for any changes on items
:
watch: {
items() {
this.itemList = this.items;
}
}
I found this other question which had a similar issue and the accepted answer did just what I just did here; however I'd like to know if this is an expected and reliable method of fixing this issue or if there are other ways to do this?
CodePudding user response:
The data property uses the prop just for initialization. It won't react to prop value changes after that.
A computed property will, though. It's another way to do it, but since you're not actually doing any "computing" on the prop value, a watcher with a function that changes the data property seems more appropriate to me.
A regular watcher is shallow, though. Your suggestion shouldn't work if the parent element just mutated the array by adding or removing elements. It should only react to a reassignment of the array (I guess that's what your parent element did... replace the prop value entirely).
If you need the watcher to react to mutations to the prop as well, then you might want to create a deep watcher:
watch: {
items: {
handler(newValue) {
this.itemList = JSON.parse(JSON.stringify(newValue)); //deep array copy to prevent array mutations made by the child component from affecting the parent's array. Keep in mind this deep-copy technique using JSON has caveats.
},
deep: true
}
}
But that can become quite expensive if your array prop grows big.
Also, it seems to me you intend for the state of your component ($data.itemList
) to be changed both by the component itself and by its parent *at the same time*. This can get troublesome (racing conditions and whatnot), so be careful.