今天和各位大佬聊聊vue3的新增的钩子函数watchEffect与watch的区别与共同之处
我们一起回到梦开始的地方,用vue写一个简单的响应式计数器
大佬说这还用写,哈哈我们直接来看代码
js
<p>计数器:{{count}}</p>
<button @click="increment">+</button>
import {
ref,
watch,
watchEffect
}
const count=ref(0)
const increment = ()=>{
count.value++
}
但今天我们来对比学习一下watch与watchEff,所以我们再写一个计数器,并且分别调用这两个钩子函数
js
<p>计数器:{{count}}</p>
<button @click="increment">+</button>
<p>计数器二:{{count2}}</p>
<button @click="count2++">+</button>
const count=ref(0)
const count2=ref(0)
const increment = ()=>{
count.value++
}
watch(count,(newValue,oldValue)=>{
//state状态的改变
console.log('count 改变了')
console.log(newValue,oldValue)
if(count.value>2){
console.log('太大了')
}
})
watchEffect(()=>{
console.log(`count 的值是${count.value}`)
console.log(`count2 的值是${count2.value}`)
})
我们来简单的看看watch函数接受的参数形式, count-响应式数据
回调函数()=>{},我们来简单说说这个newValue,oldValue,这两个变量从字面大佬应该一下猜到了,新的响应式数据和旧的响应式数据
待会儿我们还要说第三个能传进去的参数
我们来看看页面发生了什么
在我们没有点击页面的时候我们发现watchEffect函数直接执行了一次,但watch并没有,奇怪,好像组件生命周期的变化和这个钩子函数有关,没错,这就是一点不同
但是我们点击计数器1加号按钮后,当然,随着count的增大页面肯定打印了新旧count值,直到增大到2,控制台就会打印,太大了
这个大佬说,简单,不就监听这个响应式数据吗,watch和watchEffect都能实现监听,只不过watch和watchEffect的区别是一个不传参一个传参而言,对的,这就是我们要讲的第二个两者区别
我们再来看看计数器二的变化会导致两个钩子函数怎么运行,我们之后一直点击计数器二的加号,但是不点击计数器一
我们发现只有watchEffect函数运行了,所以答案显而易见,watchEffect函数会监听页面所有响应式数据的改变并执行,而watch需要配置被监听的数据
ok两点不同讲完两个不同点,我们来讲讲刚开始遗留的问题,watch函数能传的第三个参数是什么,没错就是 两个配置项 immediate和deep,这两个参数默认情况都是false我们直接手动演示一遍
js
watch(count,(newValue,oldValue)=>{
//state状态的改变
console.log('count 改变了')
console.log(newValue,oldValue)
if(count.value>2){
console.log('太大了')
}
},{
immediate:true,//默认是false,立即执行一次
deep:false//深度监听,默认是false
})
//监听,订阅发布者模式,观察者模式
watchEffect(()=>{
console.log(`count 的值是${count.value}`)
console.log(`count2 的值是${count2.value}`)
})
这是更新后的watch函数与watchEffect
我们发现第一个配置参数 immediate决定了这个钩子函数是否在组件挂载后执行一次,因为默认是false,所有我们刚刚的代码并没有一开始就打印count改变了,但我们改为true后我们发现这个函数在过载后立马执行了一次
我们再来讲讲第二个配置参数deep,了解深浅拷贝的大佬应该 大概能猜出这个deep,没错深度监听,那什么叫深度监听呢
我们先不解释这个例子,我们直接上案例
js
<p>计数器:{{count}}</p>
<button @click="increment">+</button>
<p>计数器二:{{count2}}</p>
<button @click="count2++">+</button>
<br>
{{typeof user.age}}
<p>变化:{{user.age}}</p>
<!-- 这里用的是双向绑定,v-model.number 修饰符,限定输入框转换为为数字 -->
<input v-model="user.age">
<p>变化:{{user.name}}</p>
<input type="text" v-model.number="user.name">
</div>
<script setup>
import BaseCard from './components/BaseCard.vue'
import Layout from './components/Layout.vue'
import {
ref,
watch,
watchEffect
} from 'vue'
const count = ref(0)
const count2=ref(0)
//这里自动转化成reactive对象,响应式数据结构
const user=ref({
name:'zhangsan',
age:18
})
//count 改变后做点啥
const increment = ()=>{
count.value++
}
watch(count,(newValue,oldValue)=>{
//state状态的改变
console.log('count 改变了')
console.log(newValue,oldValue)
if(count.value>2){
console.log('太大了')
}
},{
immediate:true,//默认是false,立即执行一次
deep:false//深度监听,默认是false
})
//监听,订阅发布者模式,观察者模式
watchEffect(()=>{
console.log(`count 的值是${count.value}`)
console.log(`count2 的值是${count2.value}`)
})
watch(user,(newValue,oldValue)=>{
console.log(newValue)
console.log(`user 的值是${user}`)//隐式类型转化
},{
immediate:true,
deep:true
})
</script>
依然是那个计数器,但我们来多了个复杂响应式对象,嘿嘿,这里还有一个小细节,大佬发现我们的user使用ref包裹的,但是,复杂响应式对象不因该用reatcive吗,其实这里是这样的,这个细节我们下面慢慢探讨
当您使用 ref
创建一个对象或数组时,Vue 实际上会在内部使用 reactive
来使该对象或数组成为响应式的。但是,您需要通过 .value
属性来访问或修改这个响应式数据。
我们把上述两个输入框的输入值双向设定在user这个响应式对象上,上面的 v-model.number其实是把输入框的默认字符串类型转换成number类型,大佬可以试试不加这个number,我们会发现屏幕上的{{typeof user.age}}变成了string
ok很牛逼 newValue是一个代理对象,而user是一个对象,这里涉及到ref的底层实现原理,我们后篇文章慢慢分析
那如果我们就是要看到user对象里的数据怎么办,没错JSON.stringify(user.value)
其实,上述的一切发生的原理都是建立在deep=true基础之上,为什么?其实这个时候大佬应该能大概了解深度监听是什么意思
我们来试试把deep改为false,这时我们无论怎么输入框改变user的值控制台都不会输出变化后的user对象,所有我们引出深度监听的概念
深度监听是 Vue.js 中用于监听复杂数据类型(如对象或数组)内部变化的机制。当对象或数组内部的属性或元素发生变化时,深度监听能够捕获这些变化,并触发相应的回调函数。
深度监听通常用于以下几种情况:
- 当您需要监听一个对象内部多个属性的变化时。
- 当您需要监听一个数组内部元素的添加、删除或更新时。
ok,我们试试最后一种情况,watchEffect能实现深度监听吗,我们来试试改变输入框的值,我们发现watchEffect还是自动执行了,我们来总结总结这两个钩子函数的区别
watch
- 接受三个参数
- 监视的属性名 可以是单纯响应式数据也可以是响应式数组的某一个元素
- 监视的回调函数 可以拿到新旧值
- 配置项 immediate 立即执行一次回调函数 默认是false deep 深度监视,监听对象内部属性的变化
watchEffect
- 无需指定监视的属性名,在组件挂载前自动收集响应式依赖
- 不需要配置deep深度监听,因为会自动收集依赖
- 无需配置immediate,因为会自动执行
- 副作用函数执行时机:组件挂载前,依赖的响应式数据发生变化时