Skip to content
Advertisement

Vue.js unexpected data and method behaviour

I have a Vue.js component with simple template

<div @click="createTargets(2)">
text
</div>

and script file is

export default {
  name: 'test',
  data() {
    return {
      targets: [],
    };
  },
  methods: {
    createTargets(targetCount) {
      this.targets = [];
      var emptyTarget = {
          id: null,
      };
      for (var i = 0; i < targetCount; i++) {
        var targetToPush = emptyTarget;
        targetToPush.id = i;
        console.log(targetToPush.id);
        this.targets.push(targetToPush);
        console.log(this.targets);
      }
      return {};
    },
  },
}

When I click text, I get output

0
[{"id":1},{"id":1}]
1
[{"id":1},{"id":1}]

I cannot figure out why this is happening.

I would expect

0
[{"id":0}]
1
[{"id":0},{"id":1}]

Any ideas?

Advertisement

Answer

The answer is quite simple really, an object is initialized only once, when it is assigned to a variable. If you assign this variable to a new variable, you are assigning the same object reference to a new variable. Updating Object1 will update Object2 and vice versa.

To circumvent this behavior, you can create a copy of the object when initializing Object2 using the new spread operator:

const targets = [];
const common = { commonProp: 'test' };

for (let i = 1; i <= count; i++) {
  const target = { ...common, id: i };
  targets.push(target);
}

this.targets = targets;

Note that you should avoid mutating your component’s state in a loop. Even though the render loop is optimized and won’t actually render count times, it’s still better to mutate your property only once as per example.

Also note that nested objects behave the same way. The solution above is called a shallow copy, in contrast, a deep copy will recursively crawl your object to copy sub objects/arrays.

const common = {
  commonProp: { a: 1, b: 2 }
};
const object1 = { ...common, id: 1 };
const object2 = { ...common, id: 2 };
object1.commonProp.a = 2;
console.log(object1); // { commonProp: { a: 2, b: 2 } }
console.log(object2); // { commonProp: { a: 2, b: 2 } }

To avoid this issue, you can use a library to deep copy an object/array or create a class or factory function that will return a new object every time it is called.

// factory
const createTarget = id => ({
  commonProp: { a: 1, b: 2 },
  id,
});

// class
class Target {
  constructor(id) {
    this.id = id;
    this.commonProp = { a: 1, b: 2 };
  }
}

for (let i = 1; i <= count; i++) {
  const target = createTarget(i); // or new Target(i);
  targets.push(target);
}

I hope this explanation helped you understand this concept a bit better.

Good luck 😉

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement