JAVASCRIPT

Reactive Side Effects with watchEffect

Utilize Vue 3's `watchEffect` to automatically track reactive dependencies and execute side effects, simplifying reactive logic and ensuring automatic re-execution when dependencies change.

<template>
  <div class="watch-effect-example">
    <h1>Watch Effect Example</h1>
    <p>Current Product ID: {{ productId }}</p>
    <button @click="changeProduct">Next Product</button>
    <p>Search Query: <input v-model="searchQuery" placeholder="Type to search..." /></p>
    <p>Is Loading: {{ isLoading }}</p>
    <p>Product Details: {{ productDetails }}</p>
    <p>Search Results: {{ searchResults }}</p>
  </div>
</template>

<script setup>
import { ref, watchEffect } from 'vue';

const productId = ref(1);
const searchQuery = ref('');
const isLoading = ref(false);
const productDetails = ref(null);
const searchResults = ref([]);

const fetchProductDetails = async (id) => {
  isLoading.value = true;
  productDetails.value = null;
  console.log(`Fetching details for product ${id}...`);
  // Simulate API call
  await new Promise(resolve => setTimeout(resolve, 500 + Math.random() * 500));
  productDetails.value = { id, name: `Product ${id} Name`, price: (id * 10).toFixed(2) };
  isLoading.value = false;
};

const performSearch = async (query) => {
  if (!query) {
    searchResults.value = [];
    return;
  }
  isLoading.value = true;
  searchResults.value = [];
  console.log(`Searching for: ${query}...`);
  // Simulate API call
  await new Promise(resolve => setTimeout(resolve, 300 + Math.random() * 300));
  searchResults.value = [`Result for "${query}" 1`, `Result for "${query}" 2`];
  isLoading.value = false;
};

// watchEffect will automatically track productId and call fetchProductDetails
watchEffect(async (onCleanup) => {
  // Simulate a "cancellation" for previous fetches if dependencies change quickly
  let cancelled = false;
  onCleanup(() => {
    cancelled = true;
    console.log('Product fetch cancelled.');
  });

  if (productId.value) {
    await fetchProductDetails(productId.value);
    if (!cancelled) {
      console.log('Product details updated.');
    }
  }
});

// watchEffect will automatically track searchQuery and call performSearch
// A debounce could be added here for real-world scenarios
watchEffect(async (onCleanup) => {
    let cancelled = false;
    onCleanup(() => {
        cancelled = true;
        console.log('Search cancelled.');
    });

    // Small debounce for search input
    const timeout = setTimeout(async () => {
        if (searchQuery.value) {
            await performSearch(searchQuery.value);
            if (!cancelled) {
                console.log('Search results updated.');
            }
        } else {
            searchResults.value = []; // Clear results if query is empty
        }
    }, 300);

    onCleanup(() => clearTimeout(timeout));
});

const changeProduct = () => {
  productId.value++;
};
</script>

<style scoped>
.watch-effect-example {
  font-family: Arial, sans-serif;
  padding: 20px;
  border: 1px solid #eee;
  border-radius: 8px;
  max-width: 600px;
  margin: 20px auto;
  background-color: #f9f9f9;
}
h1 {
  color: #333;
}
p {
  margin-bottom: 10px;
}
button {
  padding: 8px 15px;
  margin-right: 10px;
  background-color: #42b983;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
button:hover {
  background-color: #368a68;
}
input {
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
  width: 200px;
}
</style>
How it works: `watchEffect` in Vue 3 provides a simple way to run a function immediately and automatically re-run it whenever its reactive dependencies change. Unlike `watch`, you don't explicitly list the dependencies; `watchEffect` automatically tracks them during its first execution. This snippet demonstrates two `watchEffect` instances: one fetching product details when `productId` changes and another performing a search when `searchQuery` updates. The `onCleanup` function is particularly useful for managing asynchronous operations, allowing you to cancel pending requests if the watched dependencies change before the previous operation completes, preventing race conditions.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs