[Vue] Watch and WatchEffect

Zhentiw發表於2024-11-28

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

[Vue] Watch and WatchEffect

This is mainly due to watchis 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 };
}

相關文章