前端系列-9 Vue3生命周期和computed和watch

背景

本文介绍Vue3的生命周期和钩子函数,鉴于篇幅允许以及防止前端文章过于分散,因此将watch和computed部分之前的学习笔记也整理到本文中。这三部分是三个知识点。watch可以与pinia的$subscribe状态监听进行比较学习。

1.组件生命周期

vue的每个组件的生命周期都可以分为四个阶段:创建、挂载、更新、销毁;每个阶段的前后都提供了钩子函数,让开发者有机会在特定阶段运行自己的代码。这些钩子函数叫做生命周期钩子。

[1] setup : 最早执行的钩子函数, 在创建组件之前执行;

[2] onBeforeMount和onMounted:组件挂载前后之前的函数;

[3] onBeforeUpdate和onUpdated:组件更新前后执行的函数;

[4] onBeforeUnmount和onUnmounted:组件卸载前后执行的函数;

具体使用方式如下所示:

html 复制代码
<template>
  <div>
    <p>{{ num }}</p>
    <button @click="addNum">addNumBtn</button>
  </div>
</template>

<script lang="ts" setup>
  import { 
    ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted } from 'vue'
    
  console.log('setup')
    
  let num = ref(0)
  function addNum() {
    num.value += 1
  }
 
  onBeforeMount(()=>{
    console.log('before mount')
  })
  onMounted(()=>{
    console.log('after mount')
  })
  onBeforeUpdate(()=>{
    console.log('before update')
  })
  onUpdated(()=>{
    console.log('after update')
  })
  onBeforeUnmount(()=>{
    console.log('before unmounted')
  })
  onUnmounted(()=>{
    console.log('after unmounted')
  })
</script>

组件加载后,Console控制台显示如下:

shell 复制代码
setup
before mount
after mount

当点击addNumBtn时,当前组件发生变化,触发更新事件,Console控制台显示如下:

shell 复制代码
before update
after update

说明:以onBeforeMount为例进行说明,在setup中执行onBeforeMount(函数参数),表示注册该组件在挂载前执行的方法,函数参数实际的执行时机为组件挂载前。VUE在生成和挂载组件时,按照深度优先的策略进行,子节点挂载完成后,才挂载父节点,即服务启动后,App.vue是最后一个挂载的组件。

2.computed

computed是vue3提供的响应式计算属性,可以根据其他响应式数据的变化而自动更新自身的值,并渲染到组件上。通过使用getter函数和setter函数来实现,访问计算属性时会调用getter计算并缓存计算结果;当依赖的响应式数据发生变化事,会再次调用getter计算并缓存新的计算结果;当修改计算属性时,调用setter函数进行更新。

说明: computed使用缓存是为了减少计算次数以提高性能;只有数据发生才会重新计算

以下通过案例进行介绍:

javascript 复制代码
<script setup lang="ts">
import {ref, computed} from 'vue'

let num = ref(0);

// 在computed内部函数中定义计算逻辑
let computedNum = computed(  ()=>{return num.value * 100;}  )

function changeNum(){
  num.value++;
}
</script>

<template>
  <div>
    <div>{{num}}</div>
    <div>{{computedNum}}</div>
    <hr>
    <div @click="changeNum">修改按钮</div>
  </div>  
</template>

<style lang= "scss" scoped>
</style>

在页面上,点击修改按钮 时,num和computedNum在页面上发送变化。

如果新增一个按钮用于修改computedNum的值并触发修改,此时页面不会发生变化,浏览器控制台告警显示:[Vue warn] Write operation failed: computed value is readonly.即上述给computed传递一个函数的语法定义的计算属性为只读(不可写)。

如要求computed计算属性支持可读写,需要按如下方式修改:

javascript 复制代码
// 只读
let computedNum = computed(  ()=>{return num.value * 100;}  )

// 可读可写
let computedSetNum = computed({
    get(){
      return num.value * 123;
    },
    
    set(value) {
      num.value=value;
    }

});

说明:computed传递一个对象,对象包含了get()和set(value)方法,分别用于读数据和写数据时调用。

3.watch

在"前端系列-8 集中式状态管理工具pinia"中介绍过可以通过store对象的$subscribe监听状态的变化,一般用于全局变量,而组件内部的变量可用watch实现监听。

watch一般用于监听ref和reactive包装的响应式对象,以及它们构成的数组。在不同场景下,watch使用方式有所区别,以下结合案例分章节分别进行介绍。

3.1 ref基本变量

监听基本变量

javascript 复制代码
const num = ref(0)
 
watch(num, (newValue, oldValue) => {
    console.log('num updated', newValue)
})

在setup中直接调用watch方法进行注册监听,同时传递两个参数: [1]要监听的变量和[2]处理函数。其中, 处理函数有两个入参,分别表示更新后的值和更新前的值;当监听的变量发生变化时,处理函数会被调用。

3.2 ref 对象变量

ref对象被watch时,需要多传入一个配置对象,用于指定深度递归;否则监听的是ref对象的地址,即ref属性发生变化时,watch监听不会被触发。正确的使用方式如下:

javascript 复制代码
const person = ref({
 name: 'ewen',
 age: '19',
 address: {
  country: 'CN',
  area: 'NanJing'
 }
})

watch(person, (newValue, oldValue) => {
    console.log('person update', newValue)
},  { deep: true } )

{ deep: true }对象deep表示是否进行深度递归,即子孙属性变化时,是否触发watch监听。

初次之外,还可以配置 immediate项,true表示立即触发(创建watch监听时触发,旧值为空),false表示第一次更新时触发。

3.3 reactive对象变量

3.3.1 监听整个变量

javascript 复制代码
const person = reactive({
 name: 'ewen',
 age: '19',
 address: {
  country: 'CN',
  area: 'NanJing'
 }
})

watch(person, (newValue, oldValue) => {
    console.log('person update', newValue)
})

当person的属性(含属性的子属性...)有变化时,都会触发watch监听。

3.3.2 监听变量的某个属性

javascript 复制代码
// 监听整个person对象
watch(person, (newValue, oldValue) => {...}
// 等价于 watch(() => person, (newValue, oldValue) => {...}

// 监听person对象的某个属性
watch( () => person.name, (newValue, oldValue) => {...}

3.4 组合监听

当多个ref对象、reactive对象变化时触发相同的逻辑(如打印日志),可以分别定义watch监听;也可对这些对象进行组合监听。将前面的变量修改为数组即可,如下所示:

javascript 复制代码
// 使用时注意监听变量和参数的对应顺序
watch([() => num, person.name], ([newNum, newPerson], [oldNum, oldPerson]) => {
 console.log('data updated')
})
相关推荐
Cwhat1 分钟前
前端性能优化2
前端
熊的猫1 小时前
JS 中的类型 & 类型判断 & 类型转换
前端·javascript·vue.js·chrome·react.js·前端框架·node.js
瑶琴AI前端1 小时前
uniapp组件实现省市区三级联动选择
java·前端·uni-app
会发光的猪。1 小时前
如何在vscode中安装git详细新手教程
前端·ide·git·vscode
我要洋人死3 小时前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人3 小时前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人3 小时前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR3 小时前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香3 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q2498596933 小时前
前端预览word、excel、ppt
前端·word·excel