关于vue3 watchEffect的理解和使用
当你在 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 还有很多其他的用途,例如:
- 监听窗口大小的变化,并自适应布局。 要实现监听窗口大小的变化并自适应布局,我们可以使用 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。您可以通过调整这些值来适应您的布局需求。
- 监听 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 参数的格式和解析方式。
- 监听表单输入的变化,并校验输入是否合法等。 监听表单输入的变化,并校验输入是否合法等。 以下是一个示例组件代码:
<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 方法来处理表单的提交逻辑。
请注意,在这个例子中我们假定表单包含一个用户名和一个密码输入框,并对其长度进行了校验。您可以根据您的需求调整表单控件和校验逻辑。
- 实现停止监听 在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 函数保存在组件的实例变量中,以便在需要停止监听时能够随时访问。
- 清除函数
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 的使用,相信它一定会为您带来很多的收获!
转载自:https://juejin.cn/post/7213171664711073851