1

Problem: I have a prop in a Vue component.

props: {
  user_info: {
    type: Object,
    default() {
      return {}
    }
  }
}

I need to use this prop not only for read, but also to make some changes in it. But i cant change the prop, so i cloned it to a data variable

mounted() {
  this.clonedUserInfo = {...this.user_info}
}

clonedUserInfo is an empty object in Data option.

But when i change clonedUserInfo, my prop user_info also changes.

So is there any way to brake this Data dependency from Props?

By the way if i am cloning not a Props but a Vuex state variables - it clones fine without changing the base State variable.

Anton
  • 21
  • 3

4 Answers4

2

Yes there is a way.

mounted() {
  this.clonedUserInfo = JSON.parse(JSON.stringify(this.user_info))
}

For now you are copying by reference. And thanks to my answer you will be copying by value. Look at this SO answer to understand the difference : https://stackoverflow.com/a/430958/3956205

BTL
  • 4,311
  • 3
  • 24
  • 29
  • This will only work for certain types and will not handle circular reference. – Radu Diță Apr 15 '20 at 08:02
  • Indeed but for a normal use it works fine ! (And pretty sure `user_info` is a simple object but you never know) – BTL Apr 15 '20 at 08:09
  • Thanks a lot. But still, when i'm doing same thing with for example mapState objects/arrays - they are cloning as i expected. Whats the difference between data in props and data in state/getters? – Anton Apr 15 '20 at 08:25
1

You are shallow copying user_info.

If you only have value only vars in user_info this will work, otherwise you'll update the original values.

You need to deep copy user_info.

Radu Diță
  • 13,476
  • 2
  • 30
  • 34
0

You are creating a new object clonedUserInfo that is correct. But all objects inside of clonedUserInfo will be copied by reference.

Try smth like cloneDeep perhaps

https://lodash.com/docs/4.17.15#cloneDeep

0

LODASH

You can solve this using Lodash's CloneDeep.

npm i --save lodash.clonedeep

const cloneDeep = require('lodash.clonedeep');

NPM: https://www.npmjs.com/package/lodash.clonedeep

Docs: https://lodash.com/docs/4.17.15#cloneDeep

USE A FUNCTION

You can try this to deep clone objects:

function cloneDeepWithoutLodash(src) {
  let target = {};

  for (const prop in src) {
    if (src.hasOwnProperty(prop)) {
      if(src[prop] != null && typeof src[prop] === 'object') {
        target[prop] = cloneDeepWithoutLodash(src[prop]);
      } else {
        target[prop] = src[prop];
      }
    }
  }

  return target;
}

const source = {a: { b:2 }, c:3};
const target = cloneDeepWithoutLodash(source);

source.a.b = 100; // Lets change the source to check if target changes

console.log(source.a.b); // 100
console.log(target.a.b); // 2

IMPORTANT

Always try to avoid JSON.parse(JSON.stringify(yourObject)).

By doing this you will lose any Javascript property that has no equivalent type in JSON, like Function or Infinity. Any property that’s assigned to undefined will be ignored by JSON.stringify, causing them to be missed on the cloned object.

Also, some objects are converted to strings, like Date objects for example (also, not taking into account the timezone and defaulting to UTC), Set, Map and many others.

Maycon Mesquita
  • 4,470
  • 2
  • 21
  • 29