写点什么

不习惯的 Vue3 起步三 の computed 和 watch

作者:空城机
  • 2022 年 7 月 11 日
  • 本文字数:2336 字

    阅读完需:约 8 分钟

不习惯的Vue3起步三 の computed和watch

计算属性和侦听器

Computed 计算属性

在模板内表达式非常简单,如果在模板内放入过多的逻辑会使得模板过重并且难以维护。


示例:

<template>    <div> {{ admin.friends.filter((item)=>{ if (item.name == '李四') { return true } else return false; }).length > 0 ? `${admin.name}有李四这个朋友`: `${admin.name}没有李四这个朋友` }} </div></template>
<script setup lang="ts"> import { ref, reactive, onMounted } from "vue"; let admin = ref({ name: '张三', friends: [ { name: '李四', age: 15 } ] })</script>
复制代码


在上述例子中,div 元素中进行判断编写的就过于复杂了,此时模板不再是简单的,必须先看一下,才能意识到结果取决于admin.friend中是否有李四,如果要在模板中多次包含改计算,template会更加糟糕


对于任何包含响应式数据的复杂逻辑,都可以使用计算属性


computed: 接收一个回调函数,返回一个通过其他属性经过计算的新值,此新值是通过 ref 包装过的常量


对于上面的例子,可以使用 computed 抛出一个计算量

// 传参let showres = computed(()=>(admin)=>{    return admin.friends.filter((item)=>{         if (item.name == '李四') { return true }         else return false;     }).length > 0 ? `${admin.name}有李四这个朋友`: `${admin.name}没有李四这个朋友`})
复制代码


template中使用<div> {{ showres(admin) }} </div>即可显示,并且如果对 admin 做修改,showres 也可以生效修改,这其实与Vue2中的 computed 是一样的,只不过写法上有了一些区别


<template>    <div> {{ showres(admin) }} </div>    <button @click="change">改变</button></template>
<script setup lang="ts"> import { ref, reactive, onMounted, computed } from "vue"; let admin = ... // 传参 let showres = ...
function change() { admin.value = { name: '王五', friends: [] } }</script>
复制代码


效果:


computed 对比 methods

当然如果写一个 methods 方法来代替计算属性,也是能够实现相同的效果的,两者之间的区别在于计算属性基于反应依赖关系缓存的,只有相关响应式依赖发生改变时才会重新求值。而方法是每当触发重新渲染时,调用方法将总会再次执行函数。


比如下面:只改变数值 t,但是随着渲染刷新,methods 方法产生的 showres2 也会随之改变,而 computed 因为响应式依赖没有改变,所以不动。

<template>    <div> {{ showres }} </div>    <div> {{ showres2() }} </div>    {{ t }}    <button @click="change">改变</button></template>
<script setup lang="ts"> import { ref, reactive, onMounted, computed } from "vue"; let t = ref(1); // 传参 let showres = computed(()=>{ return new Date() })
let showres2 = ()=>{ return new Date() }
function change() { setInterval(()=>{ t.value++; }, 1000) }</script>
复制代码


效果:


使用 computed 会产生一个缓存,所以在性能上比 methods 更好,不过如果不希望缓存,也可以使用 methods。



watch 侦听器

watch API 与选项式 API this.$watch (以及相应的 watch 选项) 完全等效


当需要在数据变化时执行异步或开销较大的操作时,使用watch比使用computed更有效。


watch 有三个参数:

  • 一个想要侦听的响应式引用或 getter 函数

  • 回调函数

  • 监听的配置(可选)


对于监听的对象,ref 定义和 reactive 定义时监听方式也是不同的


对于ref

/* watch */ let count1 = ref(10), count2 = ref(20)watch(count1, (newval, oldval)=>{    console.log(newval, oldval)})// 监听多个值watch([count1, count2], (newval, oldval)=>{    console.log(newval, oldval)})function change() {    count1.value++}
复制代码


ref,可以监听单个值,也可以同时监听多个值,第一个参数直接写 ref 或者 ref 数组即可。


对于reactive:


  1. 如果将 state 对象传入 watch,只能监听到新值,对于老值是无法监听的

const state = reactive({ count: 0 })watch(state, (newval, oldval)=>{    console.log(newval.count, oldval.count)})
function change() { state.count++}
复制代码


  1. 如果想要监听 state 对象中某一属性,要使用()=> ...函数的方式,并且这样对于 count 的改变新值和老值都能监听到


watch(()=>state.count, (newval, oldval)=>{    console.log(newval, oldval)})
复制代码


  1. 如果想要监听 state 对象多个属性,可以像之前监听 ref 时一样使用[]


const state = reactive({ count: 0, age: 1 })
watch([()=>state.count, ()=>state.age], (newval, oldval)=>{ console.log(newval, oldval)})
复制代码




watchEffect

watchEffect 属于对 watch 的一些补充吧,不过大部分时候还是使用 watch 就足够了。


watchEffect:

  1. 不需要手动传入依赖

  2. 不是 lazy 初始化执行分析依赖,而 watch 是 lazy 的,页面第一次加载不会触发,除非使用immediate。watchEffect 会在 onMounted 之前调用

  3. watchEffect 无法获取老值,只能获取新值

  4. 一些异步操作放里面比 watch 更合适

  5. watch 的第三个参数是处理副作用的,watchEffect 靠第一个参数,watchEffect 第二个参数可以设置onTriggerflush等侦听器行为调试,参考 API:https://www.bookstack.cn/read/vue-3.0-zh/5b0a2b746cf872b6.md


示例:

let stop = watchEffect((onInvalidate)=>{    console.log(count1.value)    onInvalidate(()=>{        // onInvalidate清除副作用    })})// 结束watch监听stop();
复制代码


PS: 并且 watchEffect 无法对 reactive 进行监听,因为无法监测对象内部的变化

发布于: 刚刚阅读数: 4
用户头像

空城机

关注

曾经沧海难为水,只是当时已惘然 2021.03.22 加入

业余作者,在线水文 主要干前端的活,业余会学学python 欢迎各位关注,互相学习,互相进步

评论

发布
暂无评论
不习惯的Vue3起步三 の computed和watch_vue3.2_空城机_InfoQ写作社区