Home > Enterprise >  Vue 3 - Watching prop stops working after emitting to parent
Vue 3 - Watching prop stops working after emitting to parent

Time:01-11

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:

Vue SFC Playground

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.

  • Related