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 };
}