计算属性和监听属性
最后更新于:2022-04-02 08:13:30
>[success] # 计算属性 -- computed
~~~
1.基本规则和'option Api' 计算属性规则类似,返回值是一个ref 对象
~~~
>[danger] ##### 案例
~~~
1.下面案例返回是一个不变的响应式ref 对象,因此进行改写会报错
~~~
~~~
const count = ref(1)
const plusOne = computed(() => count.value + 1)
console.log(plusOne.value) // 2
plusOne.value++ // 错误
~~~
>[danger] ##### 案例
~~~
1.和 'option Api' 一样可以定义getter 和setter,传入的是一个对象
~~~
~~~
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: val => {
count.value = val - 1
}
})
plusOne.value = 1
console.log(count.value) // 0
~~~
>[success] # watchEffect
~~~
1.'watchEffect ' 是一个新的api,需要将这个单词拆解来看'watch' 和'effect' ,'effect'全称叫side effect,副作用。
关于副作用可以看这个'https://www.kancloud.cn/cyyspring/more/1979438#_31',或者思考一下你在watch里面
进行异步请求,这个请求是随时的不可控的这个就是一种副作用,所以可以理解成'watchEffect'的意思就是在观察
(watch)到变化后执行一些操作(effect)
2.哪能解决什么问题接口请求就是一个 side effect,假设我们现在用一个用户ID去查询用户的详情信息,
然后我们监听了这个用户ID, 当用户ID 改变的时候我们就会去发起一次请求,这很简单,用watch 就可以做到。
但是如果在请求数据的过程中,我们的用户ID发生了多次变化,那么我们就会发起多次请求,而最后一次返回的
数据将会覆盖掉我们之前返回的所有用户详情。这不仅会导致资源浪费,还无法保证 watch 回调执行的顺序。而
使用 watchEffect 我们就可以做到
3.使用起来他传入的是一个函数,这个函数可以响应式追踪依赖,具体来看'watchEffect' 能做什么
3.1.watchEffect 不需要指定监听的属性,他会自动的收集依赖, 只要我们回调中引用到了 响应式的属性,
那么当这些属性变更的时候,这个回调都会执行
3.2.'watchEffect ' 和'watch' 不同就是可以监听到内部所有的属性变化这点和'computed'类似,既然要可以收集
内部变化,所以'watchEffect ' 会默认初始时就会执行第一次, 从而可以收集需要监视的数据
4.调用返回值以停止侦听
5.传入'watchEffect ' 函数可以接收一个 onInvalidate 函数作入参,用来注册清理失效时的回调,失效回调会被触发
条件:
5.1.副作用即将重新执行时
5.2.侦听器被停止 (如果在 setup() 或生命周期钩子函数中使用了 watchEffect,则在组件卸载时)
6.触发时机在'update' 生命周期之前当然你可以通过配置更改
watchEffect(
() => {
/* ... */
},
{
flush: 'post'// post 是之后 默认是pre, sync,这将强制效果始终同步触发
}
)
~~~
>[danger] ##### 简单案例
~~~
1.下面案例运行后控制台打印1,即使'watchEffect' 里面没有任何指定的属性依然会执行,这也和上面的3.2点
解释符合,需要先立即执行收集内部需要被简单的数据
~~~
~~~
~~~
>[danger] ##### 简单案例
~~~
1.下面代码执行结果先打印'1 0 "w" ' 在一秒后打印 '8 1 10 "z" ',因为'watchEffect' 是立即执行因此先打印
一次,在第一次立即执行的时候收集了需要监听的响应属性,在定时器1s后执行改变了监听的响应数据,
因此'watchEffect' 被触发 -- 简单的说'watchEffect'回调里完成了自动收集响应依赖
~~~
~~~
~~~
>[danger] ##### 调用返回值以停止侦听
~~~
1.在一些情况下,也可以显式调用返回值以停止侦听,下面案例只打印了'1 0 "w" ' 在一秒后并没有打印 '8 1 10 "z" '
原因手动调用了停止响应式监听
~~~
~~~
~~~
>[danger] ##### 解释第五条清除副作用
~~~
1.下面'onInvalidate '在没有放开下面两条注释条件任意一个的时候'onInvalidate ' 不会执行,但是
放开其中任意一个条件'onInvalidate ' 都将会执行
2.说明'onInvalidate ' 会在触发监听属性改变前执行即,如果放开下面1s后执行的注释控制台打印的结果:
1 0 "w"
执行回调
1 10 "z"
所以这个'onInvalidate ' 触发跟你放的顺序无关和上面'5.1' '5.2' 条件有关
~~~
~~~
~~~
>[danger] ##### 侦听器调试
~~~
1.onTrack 和 onTrigger 只能在开发模式下工作。
onTrack 和 onTrigger 选项可用于调试侦听器的行为。
onTrack 将在响应式 property 或 ref 作为依赖项被追踪时被调用。
onTrigger 将在依赖项变更导致副作用被触发时被调用。
这两个回调都将接收到一个包含有关所依赖项信息的调试器事件。建议在以下回调中编写 debugger 语句来检查依赖关系:
~~~
~~~
watchEffect(
() => {
/* 副作用 */
},
{
onTrigger(e) {
debugger
}
}
)
~~~
>[success] ## watch
~~~
1.与watch配置功能一致
2.监视指定的一个或多个响应式数据, 一旦数据变化, 就自动执行监视回调
3.默认初始时不执行回调, 但可以通过配置immediate为true, 来指定初始时立即执行第一次
4.通过配置deep为true, 来指定深度监视
5.watch 与 watchEffect 在手动停止,副作用无效 (将 onInvalidate 作为第三个参数传递给回调),flush timing 和 debugging 方面有相同的行为
~~~
>[danger] ##### 案例
~~~
1.如果是ref 定义监听直接监听属性即可,如果是reactive 包裹的需要用返回的是getter 函数指定监听
~~~
~~~
// 侦听一个 getter
const state = reactive({ count: 0 })
watch(
() => state.count,
(count, prevCount) => {
/* ... */
}
)
// 直接侦听ref
const count = ref(0)
watch(count, (count, prevCount) => {
/* ... */
})
~~~
>[danger] ##### 监听一组
~~~
1.下面案例打印结果 ["新的count", "新str"] ["老count", "老str"],当然你也可以二次结构将值取出了例如
watch([count,str],([newCount,newStr],[oldCount,oldStr])=>{})
~~~
~~~
~~~
>[danger] ##### watch 与 watchEffect
~~~
const stop = watch([count,str],(newVaul,oldVaul,onInvalidate)=>{
console.log(newVaul,oldVaul)
onInvalidate(()=>{
})
},{
onTrigger(e){}
})
stop()
~~~
>[success] # 总结watch 与 watchEffect 不同
~~~
1.watch函数
1.1.监视指定的一个或多个响应式数据, 一旦数据变化, 就自动执行监视回调
1.2.默认初始时不执行回调, 但可以通过配置immediate为true, 来指定初始时立即执行第一次
1.3.通过配置deep为true, 来指定深度监视
2.watchEffect函数
2.1.不用直接指定要监视的数据, 回调函数中使用的哪些响应式数据就监视哪些响应式数据
2.2.默认初始时就会执行第一次, 从而可以收集需要监视的数据
2.3.监视数据发生变化时回调
~~~
';