One of the major benefits to the new Composition API in Vue 3 is how it provides a flexible and powerful reactivity system to developers. With Vue 2, developers were reliant on the Options API to build single-file components, which enforced a level of structure to how the system was used.
The Composition API, on the other hand, gives the developer new opportunities to build reactive applications. In a previous article, we explored the difference between ref and reactive methods.
Let's build on that understanding, and introduce two new methods from the Composition API - watch and watchEffect.
The Options API provided us with the watch option, which is a way to observe when values changed and perform side effects based on that.
Here's a basic example of what a watcher could look like with the Options API:.
Let's summarize what's going on here:.
In that object, we have a function, also called notes. This function will be automatically called whenever the value of notes changes (for example, when text is entered into the field).
Each watcher takes two arguments: the new value, and the previous value.
Since it's a function, we can do any validation or checks that need to happen here, and perform any side effects. In our example, when the text in the notes field changes, we are saving the value to a backend.
For further reading on watchers with the Options API, here's a link to the documentation for Vue 2. Now that we have a basic understanding of watchers in the Options API, let's dive into the Composition API!
The Composition API provides us with two different methods to handle side effects - watch and watchEffect.
Just like with ref and reactive, these methods are not meant to compete with each other, but to be used as required by the application.
Think of them as two similar tools that are each useful in certain cases.
Both of these methods do the following:. Watch for changes in reactive variables.
Allow the developer to perform side effects.
Provide a way to cancel a side effect (in case the state has become invalid). However, there are a number of differences between them as well.
Here's a short list of what makes them different:. watch can be used to lazily trigger side effects (watchEffect is always immediate). watchEffect automatically watches for changes to any state changes (watch must be provided with a variable or variables to watch).
watch provides access to the current and previous values. It's important to take into account what you want to achieve, and use the correct tool for the job.
As we work through this article, we'll do some comparison against the two options. Let's start refactoring the example above using watchEffect.
Below is the same application using the Composition API:.
Since we are using the Composition API, we use ref to instantiate the notes variable. Also, we need to use notes.value, since it is a reference to the value and not the value itself.
Finally, we return an object with notes so that it is available in the template. With watchEffect, we provide an anonymous function as an argument, then perform our side effect of saving the text.
🔗Composition API - watchEffect
Note that we don't need to provide notes as a value to be watched - watchEffect is capable of watching any reactive variables that are referenced within the callback function.
To highlight this, let's add a new variable to the mix - notesArePublic. Below is our updated application using two variables inside of the watchEffect:.
Now, whenever either notes or notesArePublic change, the side effect will be triggered and our save function will be called.
Composition API - watchEffect
This can cut down on a lot of code compared to the Options API, where you would need to create multiple watchers that do the same thing. 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.
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?
watch with immediate
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.
🔗Options API - watch in the Options API
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.
watchEffect - Tip #1
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.
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."
watchEffect - Tip #2
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?
watchEffect - Tip #3
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.