浅谈vue3的Reactivity API和Composition API


Reactivity API

响应式数据

vue3的响应式系统是脱离组件的,下面的代码可在js文件中直接执行。

reactive

reactive可以使数据变成响应式。

import {
    
    reactive} from 'vue'
//本质上,下面的代码等于new Poxy({ count: 0 })
const obj = reactive({
    
     count: 0 })

当只需要只读的代理,可以使用readonly,任何被访问的嵌套 property 也是只读的。

import {
    
    readonly} from 'vue'
const obj = readonly({
    
     count: 0 })

readonly也可以传入代理,返回新的代理,新的代理不可修改,新代理与传入的代理是不相同的。

import {
    
    reactive,readonly} from 'vue'
const obj = reactive({
    
     count: 0 })
const newObj = readonly(obj)

reactive和readonly不可以传入基本数据。

ref

我们知道Proxy只能代理对象,当我们需要代理基本数据时,我们可以使用ref。(ref啥都可以传)

import {
    
    ref} from 'vue'
const count = ref(0)
const newRef = ref(count)

console.log(count.value) //0
console.log(newRef.value) //0
console.log(newRef === count) //true

如果ref传入了一个对象,其内部会帮我们调用reactive,返回一个代理。

ref可以传入任何数据。如果传入是一个代理,则直接使用代理,所以传入的代理和新的代理是相同的。

computed

computed传入的是一个函数,返回结果是一个带value属性的对象,当读取value值的时候,会根据情况决定是否要运行函数。

函数的执行时机是在调用返回结果的value时触发。

import {
    
    ref,computed} from 'vue'
const count = ref(1)
const sum = computed(
	()=>{
    
    
		console.log("computed") //当依赖的值没发生变化时,运行多次sum.value,函数内仍然运行一次,只有当依赖发生变化时才会重新运行函数内。
		return count.value * 2
	}
)

console.log(sum.value) //先输出computed,再输出2

判断数据

vue3针对多种数据,提供了几个api让我们去判断数据的类型。

api 描述
isProxy 判断数据是否是reactive或者readonly创建
isReactive 判断数据是否是reactive创建
isReadonly 判断数据是否是readonly创建
isRef 判断数据是否是一个ref对象

转换数据

vue3针对多种数据,提供了几个api去转换数据的类型

api 描述
unRef 本质等同于 isRef(数据) ? 数据.value : 数据
toRef 将响应式对象某个属性转换为ref格式
toRefs 将代理对象的所有属性转换为一个平面对象,每个属性都是ref格式

小结

  1. vue3返回的数据格式可分为两种,一种是proxy,一种是带value属性的对象,即ref object。
  2. 如果想要让一个对象变为响应式数据,可以使用reactive或ref。
  3. 如果想要让一个对象的所有属性只读,可以使用readonly。
  4. 如果想要让一个非对象数据变为响应式,可以使用ref。
  5. 如果想要根据已知的响应式数据得到一个新的响应式数据,使用computed。
  6. toRefs主要用于setup导出与导入时的解构,建议return时统一用toRefs包装一层再解构,导入时使用toRefs包装数据再解构出来,确保数据统一。

监听数据

watchEffect

import {
    
     ref, watchEffect, reactive } from 'vue'
const state = reactive({
    
     a: 1, b: 2 })
const count = ref(0)
watchEffect(
	() => {
    
    
		//watch会自动收集依赖,数据变化时会运行该函数
		console.log("watch")
		console.log(state.a, count.value)
	}
)//立即运行
console.log(state.a)//读取a并不会执行watch,所以这里输出1
console.log(state.b)//读取b并不会执行watch,所以这里输出2
state.a++ //这里更改值,导致watch执行,所以先执行watch,输出'watch',2,0
console.log(state.a)//不会执行watch,输出2
state.b++//不触发watch
state.a++//触发watch

watch

watch需要手动指定监听的值,同vue2用法。

import {
    
     ref, watchEffect, reactive } from 'vue'
const state = reactive({
    
     a: 1, b: 2 })
const count = ref(1)

watch(
	()=>state.a,
	(newValue,oldValue)=>{
    
    
		console.log(newValue,oldValue)
	},
	{
    
    imediate:true}) //代理对象需要传函数

watch(
	count,
	(newValue,oldValue)=>{
    
    
		console.log(newValue,oldValue)
	},
	{
    
    imediate:true}) //ref直接传

watch(
	[()=>state.a,count],
	([newValue1,newValue2],[oldValue1,oldValue2])=>{
    
    },
	{
    
    imediate:true}
) //传多个值

小结

  1. 无论是watchEffect还是watch,当依赖项变化时,回调函数的运行都是加入微队列的。
  2. 一般情况下推荐使用watchEffect,因为会自动收集依赖。
  3. 当不希望回调函数立即执行,可以选择watch,虽然watch配置imediate也可以立即执行,watchEffect会立即执行一次。
  4. watch适合在监听某些数据时,当数据变化时在处理函数里做一些跟监听数据无关的事情(因为与监听数据无关代表着watchEffect没有依赖,就不会触发处理函数)。

Composition API

setup

Reactivity API可以脱离vue使用,而Compositon API与前者不同,其与vue组件深度绑定
setup的基本用法如下:

<script>
export default(){
    
    
	setup(props,context){
    
    
		//对于同一个组件,只运行一次。该函数在组件属性被赋值后立刻执行,早于其他生命周期钩子。
		//props是一个对象,包含所有组件属性。
		//context是一个对象,包含了attrs、slots、emit(同vue2的this.$attrs、this.$slots、this.$emit)等。
		
		// return的对象暴露给模板
		//这里不能直接使用ES6的解构,需要使用toRef或toRefs包装再解构,直接解构会消除响应式
		return {
    
    
			XXX,
			XXX
		}
	}
}
</script>

setup里不能使用this

3.2版本之后的vue3新增了setup语法糖,只需要在script里配置setup属性就可以不需要return。

当使用 <script setup> 的时候,任何在 <script setup> 声明的顶层的绑定 (包括变量,函数声明,以及 import 引入的内容) 都能在模板中直接使用。

<script setup>
// 变量
const msg = 'Hello!'

// 函数
function log() {
    
    
  console.log(msg)
}
</script>

生命周期

对比vue2,vue3去除beforeCreate、created,新增setup,beforeCreate和create可用setup代替。

除了setup,对比vue2其他生命周期钩子,都是在其前面加on前缀。

在vue3中,销毁是unmount。即去除beforeDestroy和destroyed,改叫onBeforeUnmount和onUnmounted。

与vue2相比,同时还新增了onRenderTracked和onRenderTriggered。

Option API Composition API
beforeCreate setup(新增)
created setup(新增)
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeUnmount onBeforeUnmount
unmounted onUnmounted
errorCaptured onErrorCaptured
renderTracked(新增) onRenderTracked(新增)
renderTriggered(新增) onRenderTriggered(新增)
activated onActivated
deactivated onDeactivated

关于新增钩子函数的说明:

  • renderTracked,参数为DebuggerEvent,触发的时机是在vnode收集到每一个依赖时。第一次刷新会触发。
  • renderTriggered,参数为DebuggerEvent,触发的时机时某个依赖变化导致组件重新渲染时。第一次刷新并不会触发。

小结

Composition API相比于Option API,优势主要体现以下两方面:

  1. Composition API可以做到更好的逻辑复用和代码组织。(Option API上下横跳问题等)
  2. Composition API具有更好的类型推导。(Option API除了this问题还有函数问题都不利于ts推导)

总结

Composition API配合Reactivity API,可以在组件内部做到更加细粒度的控制,使得组件不同功能能做到高度聚合,提升代码的可维护性和可阅读性,同时所有的api变得更加函数式,这有利于类型推导,和ts深度配合。

猜你喜欢

转载自blog.csdn.net/Mr_RedStar/article/details/123584831