I have an issue trying to watch a prop in a child component. Here's a playground link with a a little code to reproduce the issue:
The child component (in orange) inherits the data from the parent (just an array). The child component copies the data from the parent whenever it changes, and you can then modify (append) to the child data, and when you click save, the data should be emitted into the parent (and is then subsequently passed into the child as a prop).
The problem is, as soon as you click save in the child component, the child is no longer able to watch for changes to the prop. It never sees the future changes from the parent. Vue devtools correctly sees the data though. What am i missing here?
CodePudding user response:
The watch
composable accepts either a function or a ref
.
Your props.list
isn't really a reactive data, so you need to use a getter function in your watch for it to listen properly to the prop changes:
watch(() => props.list, () => {
// ...
})
See this working playground
CodePudding user response:
Try to set your watcher like:
watch(
() => props.list,
(newValue, oldValue) => {
console.log('updated!');
internalCopy.value = JSON.parse(JSON.stringify(props.list));
}, {
immediate: true,
deep: true,
}
CodePudding user response:
Issue is not in a computed property, Issue is in your onAdd
method. As this is an array, It should be update by reference
not a value
.
const onAdd = (val) => {
// data.value.list = val; ❌
val.forEach((d, index) => {
data.value.list[index] = d ✅
})
}
Working Vue SFC Playground
CodePudding user response:
It is also working well with deep watch on props
object, like so:
watch(props, () => {
console.log('updated!');
internalCopy.value = props.list;
}, {
immediate: true,
deep: true,
})
Since the ref
(reference) to the props
object keeps unchanged.
CodePudding user response:
This is a very interesting question to deeply understand the Vue reactivity. That's why I wanted to clarify it completely .
The previous answers are correct, but they don't explain the problem fully enough for me.
Since the props.list
is a ref
(reference) to the the array, when you define your watcher
with it, then the watcher is bound to this ref
(a Proxy
object) and it will stay bounded to this ref
even if you replace the props.list
with a new ref
to an new array. This is what you do with your add
event.
To check it I have added the refBackup
with the original ref
to see it the watcher still updates, it we update the original list
array through refBackup
. Like this:
const refBackup = ref(props.list);
const addToBack = () => {
refBackup.value.push('addToBack');
}
Notice that updating the refBackup
triggers the watcher()
, even after the save was clicked and the props.list
points now to another ref
with a new Array.
Here is the link to my playground
In case when you define your watcher()
with the function () => props.list
,
this function always returns the actual ref
to the last updated array. The watcher is bound to the function and not to the ref
of props.list
array.