likes
comments
collection
share

关于vue3 watchEffect的理解和使用

作者站长头像
站长
· 阅读数 25

当你在 Vue3 中使用 Composition API 来编写代码时,你会经常遇到 watchEffect 这个函数。该函数可以让你的代码更加简洁和易于阅读,因此在 Vue3 中使用它是很常见的。

那么,什么是 watchEffect 呢?

简单来说,watchEffect 是 Vue3 中的一个响应式 API,它允许您监听响应式状态的变化,并在其发生变化时触发副作用函数。这个特性非常有用,在我们需要对响应式数据进行操作的时候,我们可以在监听到变化后马上做出反应。

例如,当我们需要根据用户的位置动态更新地图的位置时,我们可以使用 watchEffect 函数:

import { watchEffect } from 'vue';

export default {
setup() {
const userLocation = reactive({ x: 0, y: 0 });

    watchEffect(() => {
      // 更新地图位置
      updateMap(userLocation.x, userLocation.y);
    });

    return { userLocation };

}
}

在这个例子中,我们创建了一个响应式对象 userLocation,然后使用 watchEffect 函数监听它。每当 userLocation 的 x 或 y 属性发生变化时,watchEffect 将自动调用副作用函数,并更新地图的位置。这样,我们就可以实现基于用户位置的动态地图。

除此之外,watchEffect 还有很多其他的用途,例如:

  1. 监听窗口大小的变化,并自适应布局。 要实现监听窗口大小的变化并自适应布局,我们可以使用 watchEffect 监听 window.innerWidth 和 window.innerHeight 属性的变化,并在响应式状态中更新该值。然后,我们可以在模板中使用这些响应式状态来动态地计算和渲染布局。 以下是一个示例组件代码:
<template>
  <div
    :style="{
      width: containerWidth + 'px',
      height: containerHeight + 'px',
      backgroundColor: 'red',
    }"
  >
    <!-- 这里是你的布局内容 -->
  </div>
</template>

<script>
import { reactive, watchEffect } from "vue";

export default {
  setup() {
    // 创建响应式对象来存储窗口宽度和高度
    const windowSize = reactive({
      width: window.innerWidth,
      height: window.innerHeight,
    });
    // 创建响应式状态来存储容器宽度和高度
    const state = reactive({
      containerWidth: windowSize.width - 20,
      containerHeight: windowSize.height - 40,
    });
    // 监听窗口大小变化并更新响应式状态
    watchEffect(() => {
      windowSize.width = window.innerWidth;
      windowSize.height = window.innerHeight;

      // 计算容器宽度和高度
      const containerWidth = windowSize.width - 20; // 减去边框和 padding
      const containerHeight = windowSize.height - 40; // 减去边框和 padding

      // 更新响应式状态
      state.containerWidth = containerWidth;
      state.containerHeight = containerHeight;
    });

    return state;
  },
};
</script>

在这个例子中,我们使用了 reactive 来创建一个响应式对象 windowSize 来存储窗口的宽度和高度,然后使用 watchEffect 监听窗口大小的变化并更新响应式状态。最后,我们使用返回的响应式状态来动态计算容器的宽度和高度,并在模板中将其应用于容器样式。

请注意,在这个例子中我们假定容器有一个10像素的边框和20像素的padding。您可以通过调整这些值来适应您的布局需求。

  1. 监听 URL 参数的变化,并更新页面内容。 要实现监听 URL 参数的变化并更新页面内容,我们可以使用 watchEffect 监听 window.location.search 属性的变化,并在响应式状态中更新该值。然后,我们可以根据响应式状态来动态地计算和渲染页面内容。 以下是一个示例组件代码:
<template>
  <div>
    <h1>{{ pageTitle }}</h1>
    <p>{{ pageContent }}</p>
  </div>
</template>

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

export default {
  setup() {
    // 创建响应式对象来存储 URL 参数
    const queryParams = reactive({});

    // 监听 URL 参数变化并更新响应式状态
    watchEffect(() => {
      const searchParams = new URLSearchParams(window.location.search);
      for (const [key, value] of searchParams.entries()) {
        queryParams[key] = value;
      }
    });

    // 根据 URL 参数计算页面标题和内容
    const pageTitle = `Welcome to ${queryParams.name}`;
    const pageContent = `We hope you enjoy your stay in ${queryParams.city}!`;

    return {
      pageTitle,
      pageContent
    };
  }
};
</script>

在这个例子中,我们使用了 reactive 来创建一个响应式对象 queryParams 来存储 URL 参数,然后使用 watchEffect 监听 URL 参数的变化并更新响应式状态。最后,我们使用返回的响应式状态来动态计算页面的标题和内容,并在模板中将其渲染出来。

请注意,在这个例子中我们假定 URL 参数包含 name 和 city 两个参数。您可以根据您的需求调整 URL 参数的格式和解析方式。

  1. 监听表单输入的变化,并校验输入是否合法等。 监听表单输入的变化,并校验输入是否合法等。 以下是一个示例组件代码:
<template>
  <div>
    <label for="username">Username:</label>
    <input id="username" type="text" v-model="username" />

    <label for="password">Password:</label>
    <input id="password" type="password" v-model="password" />

    <button @click="submitForm">Submit</button>

    <p v-if="!isValid">{{ errorMessage }}</p>
  </div>
</template>

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

export default {
  setup() {
    // 创建响应式对象来存储表单输入值
    const formValues = reactive({
      username: '',
      password: ''
    });

    // 校验表单输入值是否合法
    const isValid = () => {
      if (formValues.username.length < 3) {
        return false;
      }
      if (formValues.password.length < 6) {
        return false;
      }
      return true;
    };

    // 计算错误信息
    const errorMessage = computed(() => {
      if (!isValid()) {
        return 'Please enter valid username and password.';
      }
      return '';
    });

    // 监听表单输入值变化并更新响应式状态
    watchEffect(() => {
      formValues.username = document.getElementById('username').value;
      formValues.password = document.getElementById('password').value;
    });

    // 提交表单
    const submitForm = () => {
      if (isValid()) {
        // 执行提交逻辑
      }
    };

    return {
      username: formValues.username,
      password: formValues.password,
      isValid,
      errorMessage,
      submitForm
    };
  }
};
</script>

在这个例子中,我们使用了 reactive 来创建一个响应式对象 formValues 来存储表单输入值,并使用 watchEffect 监听表单输入值的变化并更新响应式状态。最后,我们通过计算属性 isValid 来校验表单输入值是否合法,并在模板中根据返回的结果动态显示错误信息。同时,我们也提供了一个 submitForm 方法来处理表单的提交逻辑。

请注意,在这个例子中我们假定表单包含一个用户名和一个密码输入框,并对其长度进行了校验。您可以根据您的需求调整表单控件和校验逻辑。

  1. 实现停止监听 在Vue3中,使用 watchEffect 监听响应式状态的变化时,会返回一个函数用于停止监听。当我们不再需要监听时,可以调用该函数来停止监听。

以下是一个示例代码:

import { watchEffect } from 'vue';

export default {
  setup() {
    let count = 0;

    // 开始监听
    const stopWatching = watchEffect(() => {
      console.log(`Count: ${count}`);
    });

    // 每隔1秒更新一次 count 变量
    setInterval(() => {
      count++;
      if (count > 5) {
        // 停止监听
        stopWatching();
      }
    }, 1000);
  }
};

在这个例子中,我们使用 watchEffect 监听变量 count 的变化,并每隔1秒输出当前的值。当 count 的值大于5时,调用 stopWatching 函数来停止监听。

请注意,在实际开发中,我们通常会将 stopWatching 函数保存在组件的实例变量中,以便在需要停止监听时能够随时访问。

  1. 清除函数
import { ref, watchEffect } from 'vue';

export default {
  setup(props) {
    const data = ref(null);

    const fetchData = async () => {
      // 模拟异步请求
      return await new Promise(resolve => setTimeout(() => resolve(`Data for ID ${props.id}`), 1000));
    };

    watchEffect(onInvalidate => {
      onInvalidate(async () => {
        // 在 Promise 解析之前注册清除函数
        console.log('Cleaning up...');
        // 取消未完成的异步请求
        const cancelToken = new axios.CancelToken();
        await axios.get('/cancel', { cancelToken });
        // 将响应式变量重置为 null
        data.value = null;
      });

      // 获取数据并设置响应式变量
      data.value = await fetchData(props.id);
    });

    return { data };
  },
};

在上面的示例中,我们使用了 axios 库来发起网络请求,并通过创建一个 CancelToken 实例来取消请求。在副作用函数中,我们通过调用 onInvalidate 函数来注册一个清除函数。当组件被卸载时,清除函数会自动触发,在其中包含了取消请求和将响应式变量重置为 null 的逻辑。

注意,在清除函数中,我们使用了 await 关键字等待取消请求完成。这是因为如果您不等待请求被取消,那么 watchEffect 函数可能已经被销毁,而请求仍然在后台继续,从而导致潜在的内存泄漏。

此外,由于 watchEffect 是在组件挂载时执行的,所以在第一次加载时也会触发清除函数的逻辑。如果您不希望在加载页面时触发清除函数,则可以考虑使用 watch 替代 watchEffect,并在 immediate: true 选项中设置为 false。这样,监听器的回调函数只有在依赖项发生更改时才会被触发。

总的来说,watchEffect 是 Vue3 中非常强大的一个响应式 API,它可以帮助我们更加简洁、高效地编写代码。如果您正在学习 Vue3,我强烈建议您深入了解 watchEffect 的使用,相信它一定会为您带来很多的收获!