尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Vue 中 watch 和 watchEffect 有什么区别?

Vue 中 watch 和 watchEffect 有什么区别? Vue 中 watch 和 watchEffect 有什么区别一句话总结watch 是「指定依赖、新旧值都有」的精确监听watchEffect 是「自动收集依赖、立即执行、只拿新值」的副作用运行器。需要旧值对比用 watch只需副作用响应变化用 watchEffect正文目录watch 和 watchEffect 的核心区别5 大高频场景 代码对比万能兜底什么时候用哪个预防 checklist不再踩坑一句话总结一、watch 和 watchEffect 的核心区别script setup import { ref, watch, watchEffect } from vue; const count ref(0); // watch明确指定依赖能拿到新旧值 watch(count, (newVal, oldVal) { console.log(${oldVal} → ${newVal}); // ✅ 新旧值都有 }); // watchEffect自动收集依赖立即执行只有新值 watchEffect(() { console.log(count.value); // ✅ 自动追踪 count立即执行一次 }); /script对比项watchwatchEffect依赖指定手动指定自动收集执行时机默认非立即lazy立即执行一次新旧值都有只有新值适合场景需要对比新旧值副作用响应变化多依赖数组形式函数体内访问即追踪flush 选项支持支持返回值停止函数停止函数二、5 大高频场景 代码对比① 监听数据变化发请求watch 拿不到初始值script setup import { ref, watch } from vue; const keyword ref(); // ❌ watch 默认不立即执行组件挂载后不会发请求 watch(keyword, (newVal) { fetchResults(newVal); // ❌ 初始挂载时不执行要等 keyword 变了才触发 }); // 用户进来不发请求要手动触发 onMounted(() fetchResults(keyword.value)); // ❌ 多写一遍 /script修复用 watchEffect 自动执行或 watch 加 immediatescript setup import { ref, watchEffect } from vue; const keyword ref(); // ✅ watchEffect 立即执行后续变化自动响应 watchEffect(() { fetchResults(keyword.value); // ✅ 挂载时执行一次 变化时再执行 }); /scriptscript setup import { ref, watch } from vue; const keyword ref(); // ✅ watch 加 immediate: true watch(keyword, (newVal) { fetchResults(newVal); }, { immediate: true }); // ✅ 立即执行一次 /script② 需要新旧值对比watchEffect 拿不到旧值script setup import { ref, watchEffect } from vue; const price ref(100); // ❌ watchEffect 只能拿到新值无法对比 watchEffect(() { const newPrice price.value; // ❌ 没有 oldPrice无法判断涨跌 const isUp newPrice ???; // ❌ 无法获取旧值 }); /script修复用 watch 拿新旧值script setup import { ref, watch } from vue; const price ref(100); // ✅ watch 能拿到新旧值 watch(price, (newVal, oldVal) { if (newVal oldVal) { console.log(涨了${oldVal} → ${newVal}); } else { console.log(跌了${oldVal} → ${newVal}); } }); /script③ watch 监听对象内部属性写法错误script setup import { ref, watch } from vue; const user ref({ name: 张三, age: 18 }); // ❌ 直接监听 ref 对象属性变化时触发但拿不到哪个属性变了 watch(user, (newVal, oldVal) { console.log(newVal, oldVal); // ❌ newVal 和 oldVal 指向同一对象引用类型 }); /scriptscript setup import { ref, watch } from vue; const user ref({ name: 张三, age: 18 }); // ❌ 用点语法监听不了 watch(user.name, () {}); // ❌ 报错user.name 不是 ref/reactive /script修复用 getter 函数监听具体属性script setup import { ref, watch } from vue; const user ref({ name: 张三, age: 18 }); // ✅ 用 getter 函数监听具体属性 watch( () user.value.name, // ✅ getter 返回要监听的值 (newVal, oldVal) { console.log(名字变了${oldVal} → ${newVal}); } ); /script④ watchEffect 忘了清理副作用script setup import { ref, watchEffect } from vue; const userId ref(1); // ❌ 没有清理函数userId 变化时旧请求还在跑 watchEffect(() { fetch(/api/users/${userId.value}) .then(r r.json()) .then(data { // ❌ 如果 userId 快速变化旧请求回来覆盖新数据 userData.value data; }); }); /script修复返回清理函数取消旧请求script setup import { ref, watchEffect } from vue; const userId ref(1); const controllerRef ref(null); // ✅ 用 AbortController 取消旧请求 watchEffect((onCleanup) { const controller new AbortController(); fetch(/api/users/${userId.value}, { signal: controller.signal }) .then(r r.json()) .then(data { userData.value data; }) .catch(err { if (err.name ! AbortError) console.error(err); }); // ✅ 清理函数userId 变化前取消旧请求 onCleanup(() controller.abort()); }); /script⑤ watch 监听多个源时只想要其中一个变化才执行script setup import { ref, watch } from vue; const keyword ref(); const page ref(1); const pageSize ref(10); // ❌ 任一变化都触发无法区分是谁变的 watch([keyword, page, pageSize], () { fetchResults(keyword.value, page.value, pageSize.value); }); /script修复用 watchEffect 自动收集所有依赖或拆分 watchscript setup import { ref, watchEffect } from vue; const keyword ref(); const page ref(1); const pageSize ref(10); // ✅ watchEffect 自动收集所有依赖 watchEffect(() { fetchResults(keyword.value, page.value, pageSize.value); }); /scriptscript setup import { ref, watch } from vue; const keyword ref(); const page ref(1); const pageSize ref(10); // ✅ 拆分keyword 变了重置 pagepage/pageSize 变了只刷新 watch(keyword, () { page.value 1; // keyword 变了重置到第 1 页 }); watch([page, pageSize], () { fetchResults(keyword.value, page.value, pageSize.value); }); /script三、万能兜底什么时候用哪个决策流程需要监听数据变化执行副作用吗 ├── 否 → 不用 └── 是 → 需要新旧值对比吗 ├── 是 → watch能拿到 oldVal └── 否 → 需要立即执行一次吗 ├── 是 → watchEffect 或 watch immediate └── 否 → watch默认 lazy快速参考表场景推荐原因数据变化发请求watchEffect立即执行 自动收集依赖新旧值对比涨跌判断watchwatchEffect 拿不到旧值监听对象具体属性watch getterwatch(() obj.prop, cb)多依赖副作用watchEffect自动收集不用写依赖数组条件触发变化后跳转watch只在变化时触发不立即执行定时器/事件监听watchEffect onCleanup自动收集依赖 清理万能模板script setup import { ref, watch, watchEffect } from vue; // ✅ 副作用场景watchEffect const keyword ref(); const page ref(1); watchEffect((onCleanup) { const controller new AbortController(); fetchData(keyword.value, page.value, controller.signal) .then(data results.value data); onCleanup(() controller.abort()); // ✅ 清理 }); // ✅ 对比场景watch const price ref(100); watch(price, (newVal, oldVal) { const diff newVal - oldVal; console.log(diff 0 ? 涨了${diff} : 跌了${-diff}); }); // ✅ 监听对象属性watch getter const user ref({ name: 张三, age: 18 }); watch( () user.value.age, // ✅ getter 监听具体属性 (newAge, oldAge) { console.log(${oldAge} → ${newAge}); } ); // ✅ watch 的高级选项 watch(keyword, (newVal) { search(newVal); }, { immediate: true, // 立即执行一次 deep: true, // 深度监听对象内部变化 flush: post, // DOM 更新后执行可读 DOM }); /script四、预防 checklist需要新旧值 → watchwatchEffect 拿不到旧值需要立即执行 → watchEffect 或 watch immediate: true监听对象具体属性用watch getter 函数不要直接watch(obj.prop)watch 监听对象/数组时 newVal 和 oldVal指向同一引用除非用deep clonewatchEffect 的副作用必须返回清理函数避免竞态和内存泄漏watch 的flush: ‘post’适合需要读 DOM 的场景DOM 更新后执行deep: true会深度遍历大对象有性能开销谨慎使用监听多个源用watch([a, b, c], cb)cb 参数是[newA, newB, newC]五、一句话总结「watch 精确监听拿新旧值watchEffect 自动收集立即执行」。需要对比旧值用 watch需要副作用响应变化用 watchEffect。监听对象属性用 getter副作用必须清理。选对了代码少一半最后问候亲爱的朋友们并邀请你们阅读我的全新著作 《Vue.js 3企业级项目开发实战微课视频版》
返回列表