Vue 3 Watch Object

Posted on  by admin

Getting started

In this tutorial, we are going to learn about how to watch an array of objects in Vue.js with the help of examples. Consider we have an array of objects like this. Now we need to watch any change happens in each object of a users array. First, we need to create a new component called User.vue where it handles each user data.

Now, let’s use the above component by passing a users array data inside the App.vue file. Now, we need to detect any change happens on each user inside the User.vue component. In the above code, we have used "user.name" property instead of user so that vue can detect any change happens in the user.name property.

Conclusion

Similarly, you can also watch objects by adding deep: true but in that case, we didn’t get any previous value. Sometimes, we’ve to watch for nested data in Vue 3 components. In this article, we’ll look at how to watch for nested data in Vue 3 components.

To add watchers that watch nested data in reactive properties, we can set the deep option to true .

For instance, we can write:. to watch the person object. We set deep to true to run the handler method whenever any property in it changes. The immediate property is set to true to the handler method to run when the person initial value is set. Therefore, we should see the console.log method log the val value when we set the person reactive property.

Also, we can watch any single property in an object for changes. For instance, we can write:. We have the “person.firstName” watcher to watch the person.firstName value for changes. Then the val parameter should log the value of person.firstName , which is 'jane' .

We can watch for nested data in reactive properties easily with watchers in Vue 3.

If you take a look at watch typing here (last bullet) its clear the first argument of watch can be array, function or Ref.

Adding Nested Data Watchers

props passed to setup function is reactive object (made probably by reactive()), it's properties are getters. So what you doing is passing the value of the getter as the 1st argument of watch - string "initial" in this case. Because Vue 2 $watch API is used under the hood, you are effectively trying to watch non-existent property with name "initial" on your component instance.

  • Your callback is called only once and never again.
  • Reason it is called at least once is because new watch API is behaving like current $watch with immediate option.
  • So by accident you doing the same thing like Tony Tom suggested but with wrong value.

In both cases it's not valid code if you are using TypeScript. You can do this instead:. Btw it's 2nd example of watch API docs.

  • Other way would be to convert props object using toRefs so its properties would be of type Ref and you can pass them as a 1st argument of watch.
  • I just wanted to add some more details to the answer above. As Michal mentioned, the props coming is an object and is reactive as a whole. But, each key in the props object is not reactive on its own.
  • We need to adjust the watch signature for a value in the reactive object compared to a ref value.

Just some more info even though it's not the mentioned case in the question:If we want to watch on multiple properties, one can pass an array instead of a single reference.

Related Posts

This does not address the question of how to "watch" properties. But if you want to know how to make props responsive with Vue's Composition API, then read on.

In most cases you shouldn't have to write a bunch of code to "watch" things (unless you're creating side effects after changes). The secret is this: Component props IS reactive. As soon as you access a particular prop, it is NOT reactive. This process of dividing out or accessing a part of an object is referred to as "destructuring".

In the new Composition API you need to get used to thinking about this all the time--it's a key part of the decision to use reactive() vs ref(). So what I'm suggesting (code below) is that you take the property you need and make it a ref if you want to preserve reactivity:. I sure hope the Vue wizards can figure out how to make this easier..

but as far as I know this is the type of code we'll have to write with the Composition API.

Here is a link to the official documentation, where they caution you directly against destructuring props.

A feature of the Composition API is the ability to remove watchers programmatically. Let's say that our user is done editing their notes, and wants to stop submitting values to the database. Both watch and watchEffect return a function that can be called to stop watching for changes.

Let's update our code to include a button that turns off our watcher.

When we call watchEffect, we are now saving its return as a variable, stopSaving. When the user clicks our Finish editing button, a function is called that will disable the watcher. Nice!

This can be useful when your application is watching for a certain critera to be met. Once the state is how you are watching it to be, you can stop watching, preventing your side effects from being triggered when they shouldn't be. This can help your code stay organized, and clearly communicates to other developers that a watcher is only neccessary for a certain task.

Another great feature is the ability to invalidate our side effects. In our example, what if the user enters more text after the save function has been called? By using the built-in invalidation, we can be aware when something has changed in our state and cancel our API request. Let's take a look at what that would look like.

The callback function we passed into watchEffect now has an argument - onInvalidate. This function also takes a callback as an argument, which is called when the watched state has changed. In our example, the save function is now returning a function that we are calling cancel, which can be used to abort the API request. When onInvalidate triggers, we call cancel, aborting the API request. No need to wait for the response when it's already out of date!

One thing to keep in mind is that watchEffect is immediately firing when your app loads. From the documentation, "To apply and automatically re-apply a side effect based on reactive state, we can use the watchEffect method. It runs a function immediately while reactively tracking its dependencies and re-runs it whenever the dependencies are changed." This means that immediately upon loading the page, our side effect is being triggered and data is sent to our API. This is very important to keep in mind! You may not want certain side effects (like saving an empty text field) to happen. If you need to lazily trigger effects, use the watch method instead.

Another important note: watchEffect is not watching your variables deeply. If we had a single object of data, which contained both of our variables, those variables updating would not trigger the side effect. In this case, we could convert the reactive object to refs, which would then correctly trigger our side effect.

🔗Composition API - watch

Now let's explore the watch method. We can improve it by adding some feedback to the user when their notes have been saved. To do this, we will add a new variable: showNotesSavedNotification, but we'll only show it for a specific amount of time.

Using the watch method is very similar to how we would use functions with the watch option in the Options API. In fact, according to the documentation, "The watch API is the exact equivalent of the component watch property." In our example above, whenever content is saved, the showNotesSavedNotification variable is set to true. Our watcher is then called, setting a timeout and clearing the notification after five seconds.

Let's go back to the point I made before about watchEffect being immediate. We don't really want to save an empty text field to our database - it's much more reasonable to wait for the user to enter a value first. Let's try using watch instead of watchEffect and see what benefits we get from it.

We have removed watchEffect and replaced it with watch. Did you notice that the first argument to the method is an array with both of our values? We can use this syntax to watch multiple variables, rather than being tied to a single one. In this way, we still only have to write a single watcher, which is excellent for avoiding code duplication.

Also of note - because we are watching an array, the values of value and oldValue are also arrays. For example, on the first keypress, oldValue would look like [ "", false ]. Depending on your use case, this might not be particularly helpful, but it's important to be aware of if you need to track the previous values of your watched variables.

In addition, the watch method is still providing us with the ability to remove the watcher, as well as the onInvalidate method. This is another improvement over the Options API. Regardless of whether we use watchEffect or watch, we still get the benefits of the improved API.

Let's make one last change to our application. I'd really like to bundle our notes and public status into a reactive object. Does that work with watch better than it did with watchEffect? Let's find out.

Yes, in fact, we can watch our reactive object! According to the documentation, "A watcher data source can either be a getter function that returns a value, or directly a ref". In this case, since we are using a reactive object, we can pass in a function that returns our data reactive object, and the watcher will trigger as expected.

Be aware that we technically could watch the data object directly, but this can have unintended consequences. Again from the docs, "Watching a reactive object or array will always return a reference to the current value of that object for both the current and previous value of the state. To fully watch deeply nested objects and arrays, a deep copy of values may be required."

In this case, if we were to do this:

Then both value and oldValue would be identical! This is clearly not what we meant to do. To avoid this, we are using the Spread syntax to create a new object which is both updating and being watched correctly, as well as not be passed by reference into both the current and previous values.

One more point to be aware of: because the watch method is the same as what is provided in the Options API, we also have access to its options, like deep and immediate. So if you need to watch an object deeply, or trigger side effects immediately, you can still do so with the watch method!

🔗Conclusion

Both watch and watchEffect have their uses. Both of them can be used to trigger side effects in your application. Next time you find yourself needing to trigger an effect in your code, ask yourself:

  • Does this effect need to be immediate?
  • Should it only trigger from a single source, or whenever its dependencies change?
  • Am I watching an object, or a ref?

And of course, make sure that a side effect is really the correct course of action for your use case. Side effects can often be used when either a computed property, or a method is a better choice for the situation.

Here's a link to an example of the final version of this code on Stackblitz.

One last thing - because the Composition API doesn't need to be used within Vue single-file components, there are a lot of great uses for both watch and watchEffect. Here's a great presentation from VueConf Toronto where Oscar Spencer uses the Vue Composition API with an Express app to trigger side effects on Twitter. Check it out!

Until next time!

This Dot Labs is a modern web consultancy focused on helping companies realize their digital transformation efforts. For expert architectural guidance, training, or consulting in React, Angular, Vue, Web Components, GraphQL, Node, Bazel, or Polymer, visit thisdotlabs.com.

This Dot Media is focused on creating an inclusive and educational web for all. We keep you up to date with advancements in the modern web through events, podcasts, and free content. To learn, visit thisdot.co.