vue3 watch笔记
watchEffect
const person = reactive({ count: 0, }); onBeforeMount(() => { console.log("onBeforeMount"); }); onMounted(() => { console.log("onMounted"); }); watchEffect( () => { const el = document.querySelector(".h1"); console.log(el); console.log(person.count); } );

const stop = watchEffect( () => { console.log(person.count); } ); stop ()
// 注意!异步创建,组件卸载不会停止监听
setTimeout(() => {
watchEffect(() => {})
}, 100)
watchEffect( (onInvalidate) => { onInvalidate(() => { console.log("before"); }); const el = document.querySelector(".h1"); console.log(el); console.log(person.count); } );
第一次运行是不会触发
改变数据依赖时触发
组件卸载前触发
副作用刷新时机
vue 默认会缓存副作用函数,异步刷新,多个依赖数据同时改变也只会触发一次。并且会监听组件更新函数,在组件更新前去触发副作用函数。
可给 watchEffect 传递第二个参数,options 配置对象,改变 副作用函数触发时机,和执行次数。
options 配置对象中,flush 属性有三个值,'pre'、'post'
或 'sync'
。
pre :默认配置,组件挂载前 和 组件更新前 执行副作用函数,并且会缓存副作用函数,异步刷新,同时改变多个依赖数据只会调用一次副作用函数。
post : 组件挂载后 和 组件更新后 执行副作用函数,并且会缓存副作用函数,异步刷新,同时改变多个依赖数据只会调用一次副作用函数。
sync: 组件挂载前 和 组件更新前 执行副作用函数,不会缓存副作用函数,同步刷新,同时改变多个依赖数据会多次调用副作用函数。少用sync
默认配置,例子:
const state = ref(0); const person = reactive({ count: 0, }); const change2 = () => { state.value++; person.count++; }; watchEffect( (onvalidate) => { onvalidate(() => { console.log("before"); }); const el = document.querySelector(".h1"); console.log(el); console.log(person.count); console.log(state.value); } );
默认情况下 副作用函数会在 组件挂载前 和 组件更新前 执行,并且会缓存副作用函数,异步刷新,同时改变多个依赖数据只会调用一次副作用函数
flush 属性值为 post,例子:
watchEffect( (onvalidate) => { onvalidate(() => { console.log("before"); }); const el = document.querySelector(".h1"); console.log(el); console.log(person.count); console.log(state.value); }, { flush: "post" } );
在 组件挂载后,和 组件更新后 执行,并且会缓存副作用函数,异步刷新,同时改变多个依赖数据只会调用一次副作用函数
flush 属性值为 sync,例子:
watchEffect( (onvalidate) => { onvalidate(() => { console.log("before"); }); const el = document.querySelector(".h1"); console.log(el); console.log(person.count); console.log(state.value); }, { flush: "sync" } );
在 组件挂载前,和 组件更新前 执行,不会缓存副作用函数,同步刷新,同时改变多个依赖数据就多次调用副作用函数
监听器调试
监听器配置对象中,onTrack 和 onTrigger 选项可用于调试监听器行为(开发模式)
onTrack:会在响应式数据被追踪的时候被调用。(就是数据被获取时)
onTrigger: 响应式依赖改变时被调用
例子
const state = ref(0); const person = reactive({ count: 0, }); const change2 = () => { state.value++; person.count++; }; watchEffect( (onvalidate) => { onvalidate(() => { console.log("before"); }); const el = document.querySelector(".h1"); console.log(el); console.log(state.value); console.log(person.count); }, { onTrack(e) { console.log(e, "track"); }, onTrigger(e) { console.log(e, "trigger"); }, } );
第一次自动执行,获取响应式数据依赖,触发 onTrack
改变依赖数据,触发 onTrigger
watch
监听特定的数据源,在回调函数中执行副作用,默认只有数据改变才会执行副作用函数, 不会立即调用副作用函数(可配置)
和 watchEffect 相比
- 能访问监听数据变化前后值
- 手动添加声明监听哪些数据
- 也有 onInvalidate, 会作为回调函数的第三个参数,(注意,副作用函数第二次执行才会调用 onInvalidate)
- 配置选项 flush 等.. watch 都有,多了 deep选项和 immediate 选项
监听单个数据源,例子
const state = ref(0); const person = reactive({ count: 0, }); const change2 = () => { state.value++; person.count++; }; // 侦听一个 getter watch( () => person.count, (count, prevCount) => { console.log(count, "count"); console.log(prevCount, "prevCount"); } ); // 直接侦听ref watch(state, (state, prevState) => { console.log(state, "count"); console.log(prevState, "prevCount"); });
监听多个数据源,并且配置选项,例子
const state = ref(0); const person = reactive({ count: 0, }); const change2 = () => { state.value++; person.count++; }; watch( [() => person.count, state], (arr, prevArr, onvalidate) => { console.log(arr, "arr"); console.log(prevArr, "prevArr"); onvalidate(() => { console.log("before"); }); }, { immediate: true, flush: "pre", onTrigger(e) { console.log(e, "trigger"); }, onTrack(e) { console.log(e, "track"); }, } );
监听多个数据源用数组写法,回调函数参数1和2 也变成数组,配置选项 immediate 为 ture 时,初始化时会自执行一次副作用函数, 其它的配置项和 watchEffect 没区别
监听对象或数组,什么情况下配置 deep 选项
数据类型 | 直接监听 | getter 写法 | 克隆数据,必须采用 getter 写法 |
ref | 需要deep | 需要deep | 不需要deep |
reactive | 不需要deep | 需要deep | 不需要deep |
(注意,响应式数据为对象时直接监听,用的是同一个对象的引用,导致回调函数参数1和2,改变前后数据相同)。所以要克隆一个副本监听此副本,并使用 getter 写法。
例子:
const person = ref({ name: { Anna: { count: 0 } }, }); const person2 = reactive({ name: { Anna: { count: 0 } }, }); const change2 = () => { person.value.name.Anna.count++; person2.name.Anna.count++; }; // 直接监听 ref watch( person, (person, prevPerson) => { console.log(person.name.Anna, "person"); console.log(prevPerson.name.Anna, "prevPerson"); }, { deep: true, } ); // 直接监听 reactive watch(person2, (person, prevPerson) => { console.log(person.name.Anna, "person"); console.log(prevPerson.name.Anna, "prevPerson"); }); // 监听reactive,getter 写法 watch( () => person2, (person, prevPerson) => { console.log(person.name.Anna, "person"); console.log(prevPerson.name.Anna, "prevPerson"); }, { deep: true, } );
回调函数参数 1和2 出现数据相同 的问题
克隆响应式数据再监听,需要 getter 写法
const person = reactive({ name: { Anna: { count: 0 } }, }); const change2 = () => { person.name.Anna.count++; }; watch( () => deepClone(person), (person, prevPerson) => { console.log(person.name.Anna, "person"); console.log(prevPerson.name.Anna, "prevPerson"); } );
现在 回调函数参数1和2,改变前后数据就正确了
建议:响应式数据为对象或数组用watch监听时,用 getter 写法。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!