Vue3 响应式理解——基础篇

377 阅读2分钟

开发者可以使用 Vue 3 新提供的方法 ref 和 reactive 来定义响应式变量。

用 reactive 定义响应式对象或数组

reactive() 函数可以创建一个响应式对象或数组:

import { reactive } from 'vue'
const state = reactive({ count: 0 })

使用 reactive() 函数接收一个对象或者数组,然后返回一个 Proxy 实例(ES6新特性)。其行为表现与一般对象类似,不同的点在于 Vue 能够跟踪对响应式对象的访问与更改操作,包括增加或删除操作。

所以在 Vue 3 中使用 Proxy 代替了 Object.defineProperty()方法,实现了深层次的响应式,完善了 Vue 2 中出现的响应式bug。

原理通过 Proxy 实例拦截对源对象的访问和操作(数据劫持),再通过 Reflect 修改源对象的数据。

const person = {
    name: '小明',
    age: 18
}
// 使用 Proxy 创建一个 person 对象的代理对象
const p = new Proxy(person,{
    // 有人读取了p对象的某个属性时调用
    // target表示被代理的目标对象,propName表示被访问或操作的对象属性名
    get(target, propName){
        console.log(`有人读取了p对象上的${propName}属性`);
        console.log("target",target);
        return Reflect.get(target, propName)
    },
    // 有人修改了p对象的某个属性 或 追加了某个属性时调用
    set(target, propName, value) {
        console.log(`有人修改了p对象上的${propName}属性,我要去更新页面了`);
        Reflect.set(target, propName, value);
    },
    // 有人删除了p对象的某个属性时调用
    deleteProperty(target, propName) {
        console.log(`有人删除了p对象上的${propName}属性,我要去更新页面了`);
        return Reflect.deleteProperty(target, propName)  
    }
})

用 ref 定义响应式变量

由于 reactive 无法定义响应式的原始类型数据,于是可以使用 ref 定义任何类型的响应式数据。不过定义响应式对象或数组时 ref 函数还是会通过 reactive 函数创建一个Proxy实例。

ref 函数接收接收一个任何类型的参数,返回一个引用实现的实例对象,简称引用实例(RefImpl)。在该实例中有许多属性和方法,可是原始数据的值还是通过 value 属性获得和修改。

import { ref } from 'vue'

// ref 函数返回一个引用实例,值存储在value属性
let a = ref(0) // RefImpl {... , value: 0}
let person = ref({name: '小明', age: 18})
// RefImpl {... , value: Proxy {name: '小明', age: 18}}

// 修改数据
a.value++
person.value.name = '小美'

当 ref 在模板中作为顶层属性被访问时,它们会被自动“解包”,所以不需要使用 .value

<template>
    <h1>当前a的值为:{{a}}</h1>
</template>

<script>
import { ref } from 'vue'
export default {
    setup() {
        let a = ref(0)
        return { a }
    }
}
</script>

ref 函数的原理通过 Object.defineProperty() 的 get 与 set 来实现响应式(数据劫持)