How to break reactivity in Vue for arrays and objects?

Let us move to the dark side and break some things. We will start with Vue’s reactivity.

See a couple of commonly used patterns to break reactivity in arrays and objects. And oh, there are ways of working around that if you are into boring stuff.

All the below things applicable to Vue 2 btw.

Direct Array Assignments

Let us try out with the following code -

<!DOCTYPE html>
<html>
  <head>
    <title>Test Reactivity</title>
    <script src="https://unpkg.com/vue"></script>
  </head>
  <body>
    <div id="app" style="text-align: center">
      <br />
      <br />
      <button @click="addToNumPush()">
        Add to Nums (Push)
      </button>
      <br />
      <br />
      <button @click="addToNumDirect()">
        Add to Nums (...)
      </button>
      <br />
      <br />
      {{ nums }}
    </div>

    <script type="text/javascript">
      var app = new Vue({
        el: "#app",
        data: {
          counter: 0,
          nums: [1, 3]
        },
        methods: {
          addToNumPush() {
            this.nums.push(this.counter++);
            console.log(this.nums);
          },
          addToNumDirect() {
            this.nums[10] = 99;
            console.log(this.nums);
          }
        }
      });
    </script>
  </body>
</html>

As you can see, the first button makes changes to the array nums and those changes are immediately available on button click. The second button does not seemingly make any changes. However, you will see from the console statement in developer tools that the array has indeed changed.

You can break reactivity by -

  1. Directly assigning a value against an array element - this.nums[10] = 99;
  2. Manipulating the array length - this.nums.length = 1;

Consider using this.nums.splice(10, 1, 99); if you have requirements to add or modify a specific element in the array.

You could also do a Vue.set(), but I do not recommend that option anymore.

Directly modifying props

We will use a similar example described above for objects.

<!DOCTYPE html>
<html>
  <head>
    <title>Test Reactivity</title>
    <script src="https://unpkg.com/vue"></script>
  </head>
  <body>
    <div id="app" style="text-align: center">
      <br />
      <br />
      <button @click="reactiveMod()">
        Reactive
      </button>
      <br />
      <br />
      <button @click="nonReactiveMod()">
        Non Reactive
      </button>
      <br />
      <br />
      {{ planets }}
    </div>

    <script type="text/javascript">
      var app = new Vue({
        el: "#app",
        data: {
          planets: { earth: 3, mercury: 1, mars: 4 }
        },
        methods: {
          reactiveMod() {
            this.planets = { ...this.planets, pluto: 9 };
            console.log(this.planets);
          },
          nonReactiveMod() {
            this.planets["jupiter"] = 5;
            console.log(this.planets);
          }
        }
      });
    </script>
  </body>
</html>

Break reactivity by assigning values to props-

this.planets["jupiter"] = 5;

You can work-around that behaviour by creating a new object and assigning all props from the older objects - sounds more complex than it is.

this.planets = { ...this.planets, pluto: 9 };

Or, simply by utilising the $add method that Vue provides us.

planets.$add(pluto, 9);
comments powered by Disqus