If you take a look at watch typing here (last bullet) its clear the first argument of watch can be array, function or Ref
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.
Putting It All Together
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
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.
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".
Introduction to Vue.js Watch
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.
- In this series, I'm focusing on the basics needed to start working in Vue 3 for people who might have some experience in Vue 2, but who haven't yet built anything in Vue 3.
- Check out my previous posts in the series:. Today, I'll introduce how to use methods, watch, and computed in Vue 3, and I'll also give a general comparison of watch and the new watchEffect.
The way I learn best is by connecting abstract concepts to a real world situation, so I tried to think of a simple, realistic situation for using methods, watch, and computed.
- The situation would need to demonstrate the following:. doing something to data properties to change them (using methods).
- making something else occur (i.e, a side effect) because of a change to the data properties (using watch). returning a value that is calculated based on data properties that have been changed (computed).
- I will use a real-world example of a company with employees and managers; the logic will help keep track of number of employees, number of managers, and total company headcount.
Not the most exciting example, but I really just want to keep it simple. One of the first things I need to be able to do, whether I'm using Vue 2 or Vue 3, is be able to make stuff happen with methods/functions (note: I'm using the terms functions and methods interchangeably in this section).
The magic of Vue is its reactivity, so local state updates automatically as stuff happens. The stuff that happens is often triggered by methods.
In my real-world example, I want to create a component that has a variable to represent the number of employees with buttons I click to add or subtract the number of employees, changing the headcount. I'll write functions to perform these basic actions. Here's what the rendered component looks like:.
I am familiar with the Vue 2 way of adding functions to the component: add each function to the methods object:. And the following line from the template shows that Vue 2 and Vue 3 are no different in how the methods are invoked in the template:. However, Vue 3 is different now in regards to where we write the methods in the script.
In Vue 3, I can now write my functions inside the setup function, which runs very early in the component lifecycle (before the component instance is even created).
I no longer have to write all my functions in the methods property of the options API. In this example, I have written two basic functions, and those functions are not separated into a separate methods block like in Vue 2, they are inside setup with the related logic like the variable for numEmployees.
I can make the functions available to the template by returning an object that includes them:. Notice that there is no keyword this when referring to numEmployees. Methods that are inside the setup function no longer use the keyword this to refer to properties on the component instance since setup runs before the component instance is even created.
I was very used to writing this-dot everything in Vue 2, but that is no longer the experience in Vue 3.
The use of ref() surrounding the data property is something I introduced in the last post, and it's important here. For reactivity to work in Vue, the data being tracked needs to be wrapped in an object, which is why in Vue 2, the data method in the options API returned an object with those reactive data properties.
Now, Vue 3 uses ref to wrap primitive data in an object and reactive to make a copy of non-primitive data (I've only introduced ref so far in this series). This is important to methods because it helps me understand why I see numEmployees.value inside the function rather than just numEmployees. I have to use .value to reach the property inside the object created by ref and then perform the action on that value property.
(I don't have to use the .value property in the template, however. Just writing numEmployees grabs the value). Writing all the methods inside the setup function may seem like it would get messy when there is more complexity going on in the component, but in practice, related logic could all be grouped together to run within its own function.
This is where Vue 3 starts to show its strengths. I could group all the logic for updating headcount into a function called updateHeadcount, then create a separate JS file where that logic lives. I'll actually name it useUpdateHeadcount.js, which is Vue 3 best-practice for naming this type of file (the convention of starting composables with use is discussed in the Composition API RFC in this section). Here's the useUpdateHeadcount.js file:. Now, in my component, I just have to write this in the setup function:.
Notice that I imported the useUpdateHeadcount file from a folder called composables. That's because these functions to separate out logic by shared concerns are known as composables in the Vue 3 world. I'm not going to go over all the details of how I wrote the composable and brought it back into the component file because I'll be doing a later blog post in the series about composables. In fact, I don't even have to use a composable; I can just write all my logic in the setup function since it's a very simple component. But I wanted to also make it clear that as the component gets more complicated, there is a strategy for organizing the logic, and it's one of Vue 3's most exciting features.
watch is basically the same in Vue 3, so I am happy to know that I can use it as I have before. In my example, I want to track the value of numEmployees to make sure it doesn't go below zero, since it's not possible to have negative human beings as employees. Here's my rendered component. It looks the same, but I added a disclaimer that the headcount cannot go below zero.
This restriction - not going below zero - will be managed by the logic in watch:. I specify which data property to track (numEmployees) as the first argument, and a callback as the second argument. Inside the callback, I have my logic that causes the side effect.
If numEmployees reaches below zero, that side effect happens, setting the value to zero. The callback makes sure the side effect happens on the next tick following the value reaching below zero. watch will not be triggered until that specific reactive property is changed, so if I want it to run immediately when the component is created, I can add an object with immediate: true like this:. The callback argument can also take two arguments for the new value and the old value, which makes watch useful for doing logic based on the previous state of the reactive property or just checking if a property has been changed (i.e.
it's a great debugging tool):. As for comparing watch in Vue 2 versus Vue 3, the only difference is that in Vue 3 I can now place watch inside the setup function. Like methods, it no longer has to be separated out into its own section as an option property on the component instance. However, Vue 3 also has added a similar feature that gives some different capabilities from watch: it's called watchEffect.
Vue 3 keeps watch the same, but it adds watchEffect as another way to cause side effects based on what happens to the reactive properties. Both watch and watchEffect are useful in different situations; one isn't better than the other. In this example, I will add another reactive property to the component - managers (numManagers).
I want to track both managers and employees, and I want to restrict their values going below zero. Here is the component now:. The reason I added a second reactive property is because watchEffect makes it easier to track multiple reactive properties. I no longer have to specify each property I want to track as the first argument of watch. Notice that I don't have a first argument to name the properties I'm tracking:.
Unlike watch, watchEffect is not lazy loaded, so it will trigger automatically when the component is created. No need to add the object with immediate: true. watchEffect is useful when I want to track changes to whatever property I want, and when I want the tracking to happen immediately. watch is useful when I want to be more specific about tracking just one property, or if I want to have access to the new value and/or old value to use them in my logic.
It's great having both features! One of the nice things about the Vue template is that I can write logic within double curly-braces, and that logic will be calculated based on whatever the values are represented by each variable:.
This will show a number which has been calculated, or computed, based on what numEmployees and numManagers are at the current point of time. And it will change if either of those data for numEmployees or numManagers change. Sometimes, the logic can get complicated or long. That's when I write a computed property in the script section, and refer to it in the template.
Here is how I would do that in Vue 2:. The computed property is another option that is part of the options API, and in Vue 2, it sits at the same level as methods, data, watch, and lifecycle methods like mounted. In Vue 3, computed can now be used in the setup function (I bet you didn't see that one coming). I have to import computed from Vue like this:.
To compute the number of employees and the number of managers, giving me the total headcount, I could write a computed like this:.
The only difference is that now I pass into the computed method an anonymous function, and I set it to the constant for headcount. I also have to return headcount from the setup function, along with everything else I want to be able to access from the template. At this point, I have logic that does the following:.
Adds or subtracts to the number of employees (numEmployees) or to the number of managers (numManagers). Makes sure employees and managers do not go below zero. Computes the total headcount based on any changes. And that wraps up this post in the series. Stay tuned for upcoming posts that cover topics like ref and reactive, composables, and the new v-model.
And as always, feel free to reach out on Twitter! Modified1 year, 5 months ago. I am trying to watch a prop in Vue 3 but it is strange that when I destructure it then the watcher doesn't work. But without destructuring it works as expected.
- What am I missing here? I am using Vue 3 + Vite.
- This is not working. But if I don’t destructure it then it works.
- 44 gold badges2626 silver badges4646 bronze badges.
4646 bronze badges. props passed into setup is reactive object and all reactivity is tight to the proxy around the object itself. If you take a value of the property of such object, you get either:.
Object (if the value is object), which is also reactive. Value (integer for example) which cannot be reactive by itself.
And destructuring is just value assigment:. You can use toRefs as described in docs. Now modelValue is ref so it can be passed as first argument of watch (no need to for a function) and in most places you must use modelValue.Value to get it's value. 33 gold badges4343 silver badges6767 bronze badges. 6767 bronze badges.
Destructuring the props will cause the value to lose reactivity.
So what you can do instead is use destructuring in the watch like so:. Adam OrłowskiAdam Orłowski. The following article provides an outline for Vue.js Watch. Vue.js is an easy-to-use web application framework that can be used to develop great interactive front-end applications.
Whenever there is any change in a particular property, a Vue watcher helps one to understand the component data. Vue.js has a special feature, i.e. Watcher, which helps one to keep track of a property of the component state and a function is run when the value of property changes.