Common Vue.js Development Mistakes and How to Avoid Them: Part 3 ✅
Tags: webdev, javascript, vue, productivity
Published: 2023-10-25 09:25:47

Welcome to the third installment of our series on common Vue.js development pitfalls. In this part, we're going to unravel another intriguing challenge – "**Watching Arrays**."

![magnifying glass on computer screen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lz8jduw9pswua43o2yks.jpg)

**Demystifying Array Watching in Vue 3**

Watching arrays in Vue 3 can sometimes be tricky. Have you ever tried to watch an array, confident that your syntax is spot-on, only to find that the watcher doesn't trigger as expected until you add `{deep: true}`? If you've experienced this, you're not alone. But rest assured, there's a reason behind this behavior, and it's time to shed some light on it.

Consider the seemingly straightforward code snippet below:

```
<script setup>
import { ref, watch } from "vue";

const numArr = ref([]);
const addRandom = () => {
  numArr.value.push(Math.random());
};

watch(numArr, () => {
  console.log("random number added");
});
</script>

<template>
  <button @click="addRandom">Add a random number to the array</button>
</template>
```
You'd expect that when you click the button, a random number should be added to the `numArr` array, and since we're watching the array, the console should log "random number added," right?

Well, here's where things get interesting: this won't work as expected 😧. 

Yes, the random number is added to the array. You would then ask if the array is changing and it is being watched for changes, why the heck isn't it working 🤬🤬??

You can experiment with the code and witness the changes in behavior by using this [CodeSandbox](https://codesandbox.io/s/admiring-bush-2kh5w2?file=/src/App.vue:0-314) playground. 


Now let's add the `deep: true` option to the watcher and see what happens.

```
<script setup>
import { ref, watch } from "vue";

const numArr = ref([]);
const addRandom = () => {
  numArr.value.push(Math.random());
};

watch(numArr, () => {
  console.log("random number added");
}, 
{deep: true});
</script>

<template>
  <button @click="addRandom">Add a random number to the array</button>
</template>
```
With this adjustment, you'd notice that the callback is now working as expected. But why does this make a difference? It's a valid question.

The key lies in understanding how Vue.js watches arrays. 

> When you replace an array entirely, you don't need to use the `deep `option. However, in scenarios where you're mutating the array, such as adding or removing items, or modifying existing elements, the deep option is essential.
 It ensures that Vue.js watches for changes within the array's elements.

If we were to replace the entire array, we could achieve our goal without the `deep `option. Here's an example of how you can modify our code to replace the array in its entirety:

```
<script setup>
import { ref, watch } from "vue";

const numArr = ref([]);
const addRandom = () => {
  numArr.value = [...numArr, Math.random()]
};

watch(numArr, () => {
  console.log("random number added");
});
</script>

<template>
  <button @click="addRandom">Add a random number to the array</button>
</template>
```

While this approach is effective, some might find it less intuitive compared to simply using the `push` method and enabling the `deep` option. Additionally, what adds an extra layer of complexity is the fact that in Vue 2, you didn't need to use the `deep` option for this purpose.

However, according to [Vue 3 migration guides](https://v3-migration.vuejs.org/breaking-changes/watch.html), this change was introduced as a breaking change. In Vue 3,

> "when watching an array, the callback will only trigger when the array is replaced. If you need to trigger on mutation, the `deep` option must be specified.
"

So there you have it, if you find that your callbacks aren't firing as expected, the first thing to check is whether you've included the `deep` option in your watcher. This simple addition can make a significant difference in how your Vue 3 application handles array watching.