Watch
Let’s look at another simple example using our composition API. Here’s some code that has a simple search input box, uses the search text to call an API, and returns the number of events that match the input results.
<template>
<div>
Search for <input v-model="searchInput" />
<div>
<p>Number of events: {{ results }}</p>
</div>
</div>
</template>
<script>
import { ref } from "@vue/composition-api";
import eventApi from "@/api/event.js";
export default {
setup() {
const searchInput = ref("");
const results = ref(0);
results.value = eventApi.getEventCount(searchInput.value);
return { searchInput, results };
}
};
</script>
With this code, here what happens when we use the form:
As you can see, it doesn’t seem to be working. This is because our API calling code, specifically results.value = eventApi.getEventCount(searchInput.value);
is only getting called once, during the first time setup()
is run. It doesn’t know to fire again, when our searchInput
gets updated.
Solution: watchEffect
To fix this we need to use watchEffect
. This will run our function on the next tick while reactively tracking its dependencies, and re-run it whenever the dependencies have changed. Like so:
setup() {
const searchInput = ref("");
const results = ref(0);
watchEffect(() => {
results.value = eventApi.getEventCount(searchInput.value);
});
return { searchInput, results };
}
So the first time this gets run it uses reactivity to start tracking searchInput
, and when it gets updated it will re-run our API call which will update results
. Since results
is used in our template our template will be re-rendered.
If I want to be more specific as to which source I want to watch for changes, I can use watch
instead of watchEffect
, like so:
watch(searchInput, () => {
...
});
Also, if I need access to the new value and old value of the item being watched I can write:
watch(searchInput, (newVal, oldVal) => {
...
});
Watching Multiple Sources
If I want to watch two Reactive References I can send them inside an array:
watch([firstName, lastName], () => {
...
});
Now if either are changed, the code inside will re-run. I can also get access to both of their old and new values with:
watch([firstName, lastName], ([newFirst, newLast], [oldFirst, oldLast]) => {
...
});
Watch is Lazy
setup() {
const searchInput = ref("");
const results = ref(0);
watch(searchInput, () => {
results.value = eventApi.getEventCount(searchInput.value);
});
return { searchInput, results };
}
We can see that Number of events in page starts with empty
This is mainly due to watch
is lazy, if you want it run immediately, you can do
setup() {
const searchInput = ref("");
const results = ref(0);
watch(searchInput, () => {
results.value = eventApi.getEventCount(searchInput.value);
}, {immediate: true});
return { searchInput, results };
}