How to use Vue 2.0 reactivity using objects?

60 Views Asked by At

I have a parent component with certain data:

data: function() {
        return {
           initialItem: { name: "item", size: 10, description: "some text" }
           currentItem: null
        };
    },
mounted() {
  this.currentItem = _cloneDeep(item);
}

and in the parent template I pass currentItem as a prop:

<child-component :item="currentItem" @set-item=updateItem />
<button @click="discardChanges">Discard changes</button>

updateItem(item) {
   this.currentItem = item
}

discardChanges() {
  this.currentItem = this.initialItem
}

The item in the UI that I want to update lives in the child component, e.g.:

<input :value.sync="itemDetail.name" @click=emit('set-item') />
(...other similar inputs)

<script>
   export const ChildComponent = {
    props: {
        item: {
            type: Object,
            required: true
        }
    },
    data: function() {
        return {
            itemDetail: this.item
        };
    },
};

Whenever the user changes an attribute in the child component, an event is emitted to the parent component, for further saving it.

The problem resides in the discard handler because even though the variable changes their attributes accordingly, the UI is not reflecting it.

I have also tried using in the discardChanges function Vue.set(...), this.$forceUpdate(), doing this.currentItem = null; this.currentItem = this.initialItem; but none of this seemed to have worked so far.

Can someone point me to what I may be missing here so that the item returns to its initial values when someone clicks the discard button?

2

There are 2 best solutions below

0
On BEST ANSWER

A possible reason to why this is happening is that when you click the discard changes button, the value of currentItem is set back to its initial value but that change does not cause the child component to render the property that changed.

The child component receives the property as a prop, and it does not create a reactive dependency. Therefore, changes to the prop in the parent component will not automatically propagate to the child component

What you can do the is add a watcher inside your child component. Once the prop value changes, you update it in the child component as well.

So within your child file, add something like this:

watch () {
  item () {
    this.itemDetail = this.item // deep copy if needed
  }
0
On

The key Changing Technique could do the trick, as this will help re-rendering your child component.

  1. Add a key to your child component :

<child-component :key ="componentKey" :item="currentItem" @set-item=updateItem />

  1. Add the componentKey property to your parent component data :
data: function() {
        return {
           initialItem: { name: "item", size: 10, description: "some text" }
           currentItem: null,
           componentKey: 1,
        };
    },
  1. Update key on item change :
updateItem(item) {
   this.currentItem = item
   this.componentKey ++
}

discardChanges() {
  this.currentItem = this.initialItem
  this.componentKey ++
}
```