Vue3 响应式数据

一、什么是响应式数据?

在 Vue 中,所谓的 “响应式数据”,是指数据具有响应性,数据层(模型)的改变会自动触发数据表示层(视图)的改变。

二、选项式 API 中的响应式数据

在 选项式 API 中,数据的响应化对程序员是 透明 的。只需要在 data 选项中填入相应的数据,Vue 会自行做响应化处理。

三、组合式 API 中的响应式数据

在组合式 API 中,数据的响应式处理需要由程序员手动处理。

下面将详细说明:

四、reactive

1. reactive()

  • 作用:根据一个对象生成 reactive 对象,它是响应式的代理对象

  • 只能处理引用类型

  • “深层处理”,会影响所有嵌套属性

  • 原对象与 reactive 对象是相互关联的

    如果修改 reactive 对象,则原对象会同步更新;

    如果修改原对象,reactive 对象也会同步更新。

    因为 reactive 对象实质上是原对象的代理,两者指向相同的内存空间。

    需要注意的是:

    如果直接修改原对象,虽然数据都会更新,但 reactive 对象和 Vue 都无法察觉到数据的更新,因此应该通过 reactive 对象进行数据的修改。

1
let rObj = reactive(obj)

2. shallowReactive()

reactive() 的区别在于:不会进行 “深层处理”。

3. isReactive()

检查对象是否是 reactive 对象。

4. 获取 reactive 的属性

如果希望获取 reactive 对象的属性的值,应该通过 reactive名.属性名 获取。

如果希望获取 reactive 对象的属性且不丢失响应性,

  • 不能够直接获取,否则获取的是值
  • 不能够简单地使用解构语法 let { 属性名 } = reactive名 ,否则获取的是值
  • 不能够简单地 ref(reactive名.属性名),否则只是根据值生成了 ref,不会与原先的属性相关联

正确的做法如下:

  • 通过 toRefs() 获取一个 “普通” 对象,该对象中包含原对象中每个属性对应的 ref 对象,每个 ref 对象都会与对应属性 “响应式连接”

    1
    let propertysRefObj = toRefs(reactive名)
  • 通过 toRef() 获取指定属性对应的 ref 对象,ref 对象会和原属性 “响应式连接”

    1
    let propertyRef = toRef(reactive名, '属性名')

五、ref

1. ref()

  • 作用:根据值生成一个 ref 对象,它是响应式的

  • ref 对象包含且只包含一个名为 value 的属性,该属性即是目标值。可以将 ref 对象理解为对目标值的引用,并且这个引用是响应式的,因此可以将 ref 称为 响应式引用响应式 ref

  • 能够处理基本类型,能够处理引用类型

    当 ref 处理引用类型时,并不会直接将引用类型作为 value,而是在内部根据引用类型生成 reactive 对象,将 reactive 对象作为 value

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <script>
    import {reactive, ref} from "vue";

    export default {
    name: "RefAndReactive",
    setup() {
    let person = {
    name: 'Tom',
    age: 11
    }
    let RefPerson = ref(person)
    console.log(RefPerson)
    console.log(RefPerson.value)
    let ReactivePerson = reactive(person)
    console.log(ReactivePerson)
    }
    }
    </script>

  • 值的访问:

    • 如果要访问值,应该通过 ref名.value 访问
    • 如果要在选项式 API 和模板中访问值,无需也不应添加 .value,会自动添加
    • 如果 ref 对象被作为 reactive 对象的属性,无需也不应添加 .value
  • 如果值是基本类型,值与 ref 对象之间是没有任何关联;

    如果值是引用类型,值与 ref 对象之间是相互关联的

    因为引用类型的值会被转为 reactive 对象

    需要注意的是:

    同样不应直接修改原对象,以免修改无法被监听。

1
let rValue = ref(value)

3. toRef()

传入一个响应式对象和属性名,获取指定属性对应的 ref 对象,ref 对象会和原属性 “响应式连接”。

即使属性不存在,toRef() 也会返回一个可用的 ref 对象。

4. toRefs()

传入一个响应式对象,返回一个 “普通” 对象,该对象中包含原对象中每个属性对应的 ref 对象,每个 ref 对象都会与对应属性 “响应式连接”。

5. isRef()

检查对象是否是 ref 对象。

2. unref()

如果传入 ref 对象,返回原值;否则,直接返回传入值。

本质上是一个语法糖,如下:

1
2
3
unref(val) {
return isRef(val) ? val.value : val
}

6. customRef()

创建自定义的 ref 对象,略。

7. shallowRef()

ref() 的区别在于:如果传入引用类型,将不会对其做 reactive 处理。

8. triggerRef()

配合 shallowRef() 使用,用于手动更新值。

因为如果不做 reactive 处理,ref 对象将无法监听到引用类型数据的改变(除非改变指针)。

9. 响应式 ref 和模板 ref

由于该问题和组合式 API 关系更加密切,因此放置在组合式 API 的部分中,具体请看:

Vue3 组合式API - 响应式 ref 和 模板 ref

五、其它 API

1. isProxy

检查对象是否由 reactive 或 readonly 创建。

2. readonly

(1) readonly()

接收一个对象(可以是普通对象、reactive 对象、ref 对象),返回 readonly 对象,它是响应式的、只读的代理对象

需要注意的是:

  • “深层处理”,只读代理对象的任何嵌套属性都只读
  • 原对象不是只读的

(2) shallowReadonly()

readonly() 的区别在于:不会进行 “深层处理”。

(3) isReadonly()

检查对象是否是 readonly 对象。

3. Raw

(1) toRaw()

根据 reactive 对象或 readonly 对象,获取它们对象的原始对象。

有以下两个作用:

  • 为了使用时去除代理带来的额外开销
  • 用于临时修改数据,且不希望被监听

(2) markRaw()

标记一个对象,使其永远无法转变为代理对象。

参考