前端系列-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')
})
相关推荐
(⊙o⊙)~哦24 分钟前
JavaScript substring() 方法
前端
无心使然云中漫步1 小时前
GIS OGC之WMTS地图服务,通过Capabilities XML描述文档,获取matrixIds,origin,计算resolutions
前端·javascript
Bug缔造者1 小时前
Element-ui el-table 全局表格排序
前端·javascript·vue.js
xnian_1 小时前
解决ruoyi-vue-pro-master框架引入报错,启动报错问题
前端·javascript·vue.js
麒麟而非淇淋2 小时前
AJAX 入门 day1
前端·javascript·ajax
2401_858120532 小时前
深入理解MATLAB中的事件处理机制
前端·javascript·matlab
阿树梢2 小时前
【Vue】VueRouter路由
前端·javascript·vue.js
随笔写4 小时前
vue使用关于speak-tss插件的详细介绍
前端·javascript·vue.js
史努比.4 小时前
redis群集三种模式:主从复制、哨兵、集群
前端·bootstrap·html
快乐牌刀片884 小时前
web - JavaScript
开发语言·前端·javascript