14
votes

In vue.js what is the right way to edit prop without changing parent data? What I mean by that is whenever we pass any property from parent to child in vue.js then if we make any change to that property in child component then the change is also reflected in parent's component.

Is there any way in vue.js to make a local copy of passed property in a child?

I googled this but everywhere it is written that we can achieve this by doing this.

 props:["user"],
  data(){
    return {
      localUser: Object.assign({}, this.user)
    }
  }

here the user is passed an object and I am creating a copy of it in local user but it doesn't work at all, the local user is undefined.

Have you encountered a scenario like this where you have to make changes to a parent property in child component without affecting the state of parent component i.e- making your own copy in child and then edit it?

Any insights on this will be helpful.

I have also read somewhere that in In [email protected],when we want to pass a prop from Father to Child component, we need to manually create a local data to save the prop, that makes lots of useless works.

we can maually create the local data like this :

props: ['initialCounter'],
data: function () {
    return { counter: this.initialCounter }
}

but this is not working in my case as well. I am using vue cli 3.0.1 for the developemnt purpose.

Here is my code for the same.

In my application I have a list view.

enter image description here

When user clicks on the See Focused View button user is redirected to below mentioned view i.e is actaully a bootstrap - modal view.

enter image description here

Here user can edit the value of Name, but as I am passing name here as a property from aprent component so editing it here causes it to update on parent component as well i.e in the list view as well.

1
Apart from that I have already tried this { this.localUser = Object.assign({}, this.user) } and this as well this.localUser = JSON.parse(JSON.stringify(this.user)) - Divyanshu Rawat
Even I have tried lodash ._clone as well, although I have resolved the provblem by binding the inputs to a local variable in data() { x: null } and binding @input = "x" then calling 2 function set and unset , one unsets edited value to original value and other sets it to x. - Divyanshu Rawat
@DivyanshuRawat Using Object.assign as you mentioned should work, as shown in this demo. - tony19
@tony19 Hey thanks, you are right but see this, your solution does not holds true when you load data from a json file in you app.vue main state, for more info. please see the repo. - github.com/divyanshu-rawat/stack-discuss I maybe wrong but please do correct me. - Divyanshu Rawat
@tony19 you can follow this fiddle for easy of access - codesandbox.io/s/j4n13vxw6w - Divyanshu Rawat

1 Answers

23
votes

In your fiddle, the child component is using Object.assign() to create a copy of data, which is an array of objects. However, this only creates a shallow copy, so the array elements would still refer to the original instances, leading to the behavior you're seeing.

A few solutions to deep copy the array:

  • Use JSON.parse(JSON.stringify(this.data)), which works reasonably well for objects of strings and numbers:

    data() {
      return {
        local_data: JSON.parse(JSON.stringify(this.data))
      }
    }
    

    (demo 1)

  • Map the objects into new ones, which works well if the depth is only 1 (nested arrays/objects will still be shallow copied):

    data() {
      return {
        local_data: this.data.map(x => ({...x}))
      }
    }
    

    (demo 2)

  • Use a utility library, such as lodash's cloneDeep:

    data() {
      return {
        local_data: _.cloneDeep(this.data)
      }
    }
    

    (demo 3)