vue2升级vue3:vue3中的watch和watchEffect细讲
Author:zhoulujun Date:
之前在vue2写过:《vue中methods/watch/computed对比分析,watch及computed原理挖掘》、《watch性能优化:vue watch对象键值说明-immediate属性详解》,vue3的watch 与vue2 其实大同小异,但是还是细讲一下。
vue3 监听数据不止有watch,还有watchEffect(写法和用法都有区别!)
watch
首先看官方文档:
https://vuejs.org/api/reactivity-core.html#watch
https://cn.vuejs.org/api/reactivity-core.html#watch
// 侦听单个来源 function watch<T>( source: WatchSource<T>, callback: WatchCallback<T>, options?: WatchOptions ): StopHandle // 侦听多个来源 function watch<T>( sources: WatchSource<T>[], callback: WatchCallback<T[]>, options?: WatchOptions ): StopHandle // 监听属性设置 interface WatchOptions extends WatchEffectOptions { deep?: boolean // 默认:false ,当需要对响应式对象进行深度监听时,设置deep: true。 immediate?: boolean // 默认:false(watch是惰性的),需要在初始化执行回调函数需要设置为true flush?: string // 默认:'pre'(指定的回调应该在渲染前被调用),post 值是可以用来将回调推迟到渲染之后的。如果回调需要通过 $refs 访问更新的 DOM 或子组件,那么则使用该值。如果 flush 被设置为 sync,一旦值发生了变化,回调将被同步调用(少用,影响性能)。
第一个参数(WatcherSource)是侦听器的源。这个来源可以是以下几种:
一个函数,返回一个值,例如: watch( () => state.count,(count, prevCount) => {})
一个 ref
一个响应式对象
...或是由以上类型的值组成的数组
第二个参数(Callback)是在发生变化时要调用的回调函数。这个回调函数接受三个参数:
新值
旧值
用于注册副作用清理的回调函数。
第三个参数(WatchOptions)可选的参数是一个对象,支持以下这些选项:
immediate:在侦听器创建时立即触发回调。第一次调用时旧值是 undefined。
deep:如果源是对象,强制深度遍历,以便在深层级变更时触发回调。参考深层侦听器。
flush:调整回调函数的刷新时机。参考回调的刷新时机及 watchEffect()。
默认值是 pre,指定的回调应该在渲染前被调用。
post 值是可以用来将回调推迟到渲染之后的。如果回调需要通过 $refs 访问更新的 DOM 或子组件,那么则使用该值。
如果 flush 被设置为 sync,一旦值发生了变化,回调将被同步调用(少用,影响性能)。
onTrack / onTrigger:调试侦听器的依赖。参考调试侦听器。
该回调函数会在副作用下一次重新执行前调用,可以用来清除无效的副作用,例如等待中的异步请求。
当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值。
watch监听多个数据
监听单个数据源没有啥好讲的:
const state = reactive({ count: 0 }) watch(() => state.count, (count, prevCount) => {}) const count = ref(0) watch(count, (count, prevCount) => {})
当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值:
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => { /* ... */ })
这里要确保数据对于的顺序
停止watch
同步语句创建的监听器,会自动绑定到组件实例上,并且会在组件卸载时自动停止,但是,如果我们在异步回调里创建一个监听器,那它就不会绑定到当前组件上,必须手动去停止,防止内存泄漏。
那怎么去停止呢,其实我们只需要调用一下watch或watchEffect返回的函数
// 直接侦听ref const ageRef = ref(16) const stopAgeWatcher = watch(ageRef, (value, oldValue) => { console.log(value, oldValue) if (value > 18) { stopAgeWatcher() // 当ageRef大于18,停止侦听 } })
停止watchEffect代码雷同
Watch使用注意事项:
当将引用对象采用ref形式定义时,如果不加上deep:true,watch是侦听不到值的变化的;而加上deep:true,watch可以侦听到数据的变化,但是当前值和先前值一样,即不能获取先前值。当将引用对象采用reactive形式定义时,不作任何处理,watch可以侦听到数据的变化,但是当前值和先前值一样。两种定义下,把watch的数据源写成getter函数的形式并进行深拷贝返回,可以在watch回调中同时获得当前值和先前值。
结论: 当我们使用watch侦听引用对象时
若使用ref定义的引用对象:
只要获取当前值,watch第一个参数直接写成数据源,另外需要加上deep:true选项
若要获取当前值和先前值,需要把数据源写成getter函数的形式,并且需对数据源进行深拷贝
若使用reactive定义的引用对象:
只要获取当前值,watch第一个参数直接写成数据源,可以不加deep:true选项
若要获取当前值和先前值,需要把数据源写成getter函数的形式,并且需对数据源进行深拷贝
来源:Vue3中watch的最佳实践 https://juejin.cn/post/6980987158710452231
watchEffect
官网:https://cn.vuejs.org/api/reactivity-core.html#watcheffect
立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行。
使用watchEffect 我们并不需要传入一个特定的依赖源,而且它会立即执行一遍回调函数,如果函数产生了副作用,那它就会自动追踪副作用的依赖关系,自动分析出响应源。
当任何你有用到的响应式依赖更新时,该回调函数便会重新执行(computed 其实类似一个带输出的同步版本的 watchEffect)。
什么是副作用(side effect)
简单的说副作用就是执行某种操作,如对外部可变数据或变量的修改,外部接口的调用等。
副作用函:会产生副作用的函数被称为副作用函数。
副作用呢:如果几个函数的运行,可能会影响到其他函数或变量,那么这种影响就是一种副作用。
我们来看两个例子:
function changeText(text: string) { document.body.innerText = text } function getText() { return document.body.innerText }changeText函数会修改body的内容。getText会返回body的内容。如果我们使用changeText修改了body内容,那么会影响到getText获取内容,那么这时changeText就是个副作用函数。副作用函数不一定非要对某些函数产生副作用,如果一个函数修改了全局变量,这其实也是个副作用函数。
var flag = true function changeFlag() { flag = !flag }changeFlag函数会更改一个全局变量flag,那么这也是一种副作用,所以changeText也是个副作用函数。
来源:认识副作用函数与响应式数据 https://segmentfault.com/a/1190000042037131
watchEffect的回调函数就是一个副作用函数,因为我们使用watchEffect就是侦听到依赖的变化后执行某些操作。
watch和watchEffect的区别
watch是惰性执行的,而watchEffect不是,不考虑watch第三个配置参数的情况下,watch在组件第一次执行的时候是不会执行的,只有在之后依赖项变化的时候再执行,而watchEffect是在程序执行到此处的时候就会立即执行,而后再响应其依赖变化执行。
watch需要传递监听的对象,watchEffect不需要——watchEffect 无法访问侦听数据的新值和旧值。
参考类:
https://www.thisdot.co/blog/vue-3-composition-api-watch-and-watcheffect
https://www.thisdot.co/blog/understanding-side-effects-in-vuejs
Vue3中watch的最佳实践 https://juejin.cn/post/6980987158710452231
vue3之watch和watchEffect实战总结 https://juejin.cn/post/7124948096798162957
转载本站文章《vue2升级vue3:vue3中的watch和watchEffect细讲》,
请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/vue3/8878.html