Vue 3响应式系统全解析:深入ref、reactive、computed、watch及watchEffect

本文主要是介绍Vue 3响应式系统全解析:深入ref、reactive、computed、watch及watchEffect,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、ref与breactive

宏观角度看:

  • 1.ref 用来定义:基本类型数据、对象类型数据
  • 2.reactive 用来定义:对象类型数据

区别:

  • 【ref 】创建的变量必须使用.value
  • 【reactive】 重新分配一个新对象,会失去响应式(可以使用0biect.assign 去整体替换)。

使用原则:

  • 1.若需要一个基本类型的响应式数据,必须使用ref
  • 2.若需要一个响应式对象,层级不深,ref、reactive 都可以。
  • 3.若需要一个响应式对象,且层级较深,推荐使用reactive

二、toRefs与toRef

1.toRef

  • 作用:从 reactive 对象中提取单个属性,创建一个 ref。
  • 使用场景:当你需要对 reactive 对象的某个具体属性进行单独的响应式处理时。

基本用法

import { reactive, toRef } from 'vue';
const person = reactive({ name: 'John Doe' });
const nameRef = toRef(person, 'name');
console.log(nameRef.value); // John Doe

2.toRefs

  • 作用:将 reactive 对象转换为多个 ref 对象的集合。
  • 使用场景:适用于需要将整个 reactive 对象的多个属性分别作为 ref 处理的情况。

基本用法

import { reactive, toRefs } from 'vue';const person = reactive({ name: 'John Doe', age: 30 });
const { name, age } = toRefs(person);
console.log(name.value); // John Doe
console.log(age.value);  // 30

结论

  • toRef 创建单个 ref,用于单个属性的响应式绑定。
  • toRefs 创建多个 ref,用于将整个对象的属性分别响应式绑定。
  • 选择使用 toRef 或 toRefs 取决于你需要对 reactive 对象执行的响应式操作的复杂性。

三、computed计算属性

计算属性是 Vue 3 中一种特殊的响应式变量,它根据其他响应式数据自动计算值。

基本用法

import { computed, ref } from 'vue';
const count = ref(0);
const doubledCount = computed(() => count.value * 2);

特点

  • 自动更新:当依赖的数据变化时,计算属性会自动重新计算。
  • 惰性计算:只有当依赖项变化时,计算逻辑才会执行。
  • 结果缓存:多次访问计算属性会得到相同的结果,而不会重复计算。

四、watch

作用:监视数据的变化(和 Vue2 中的 watch 作用一致)
特点:Vue3 中的 watch 只能监视以下四种数据:

1.ref 定义的数据。
2.reactive 定义的数据。
3.函数返回一个值(getter 函数)。
4.一个包含上述内容的数组。

watch 监听

⭐情况一

监视【ref】 直接写数据名即可,监视的是其 value 值的改变。

示例:

import { watch, ref } from 'vue';const count = ref(0);// 监视 ref 'count' 的变化
watch(count, (newValue, oldValue) => {console.log(`变化前:${oldValue} 变化后: ${newValue}`);
},{deep: true,       	// 深度监听 state 对象内部的变化immediate: true,  	// 当设置为 true 时,watch 会在开始监视后立即执行一次回调函数。flush: 'pre',     	// 控制副作用(如 DOM 更新)的刷新时机。可以是 'pre' 或 'post',或者一个包含这些值的数组。onTrack: () => {},  // 依赖项被追踪时调用onTrigger:() =>{},  // 依赖项变化时调用computed: true    	// 计算属性模式
});

⭐情况二

监视【ref】深层要手动开启深度监视

注意:
若修改的是ref定义的对象中的属性,newValue 和 oldValue 都是新值,因为它们是同一个对象。
若修改整个ref定义的对象,newValue 是新值, oldValue 是旧值,因为不是同一个对象了。

示例:

import { watch, ref } from 'vue';const person = ref({ name: 'John', age: 30 });// 监视 ref 'person' 的深层属性变化
watch(() => person.value, // 使用函数返回 ref 的 value,以确保每次都是最新的值(newValue, oldValue) => {// 回调函数会在 person 对象的属性变化时触发console.log(`变化前:${oldValue.name} 变化后:${newValue.name}`);},{ deep: true } // 开启深度监视
);

在这个例子中:

  • person 是一个通过 ref 创建的响应式引用,它包含一个对象,该对象有 name 和 age 属性。
  • 使用 watch 函数并传入一个函数,该函数返回 person.value。这样做是因为我们需要监视 person 对象内部属性的变化,而不是 person 这个引用本身。
  • 参数 { deep: true } 开启了深度监视,这样 watch 就能够追踪到对象内部属性的变化。
  • 当 person 对象的 name 或 age 属性发生变化时,提供的回调函数会被触发。

注意事项

  • 当你监视 ref 定义的对象并开启深度监视时,newValue 和 oldValue 将代表对象内部发生变化的属性的新旧值。
  • 如果整个 ref 定义的对象被一个新的对象替换,那么 newValue 将是新对象,而 oldValue 将是旧对象。
  • 开启深度监视可能会带来性能上的考虑,因为它会增加 Vue 需要追踪的变化的数量。

⭐情况三

监视【reactive】定义的【对象类型】数据,默认开启深度监视(无法关闭)

示例:

import { reactive, watch } from 'vue';// 使用 reactive 创建一个响应式对象
const person = reactive({name: 'John',details: {age: 30}
});// 监视 reactive 对象的 'details.age' 属性
watch(() => person.details.age,(newValue, oldValue) => {console.log(`Age changed from ${oldValue} to ${newValue}`);}
);

在这个例子中:

  • person 是一个使用 reactive 创建的响应式对象,它包含一个名为 details 的属性,该属性本身也是一个对象,包含 age 属性。
  • 使用 watch 来监视 person.details.age 属性的变化。由于 reactive 默认进行深度监视,因此不需要额外的 deep 选项即可追踪到 details 对象内部的 age 属性变化。

注意事项

  • reactive 创建的响应式对象总是深度监视的,这意味着你无法关闭这个行为。
  • 当你使用 watch 来监视 reactive对象的属性时,即使属性是嵌套的,也不需要 deep 选项,因为深度监视是自动应用的。
  • 如果 reactive 对象的某个属性也是一个对象,并且你想要监视这个嵌套对象的属性,你可以直接使用 watch,并提供一个返回该嵌套属性的函数。

通过这种方式,Vue 3 的 reactive API 提供了一种直观且强大的方式来创建和管理响应式状态,同时 watch API 允许你监视这些状态的变化,无需担心监视的深度问题。

⭐情况四

监视响应式对象中的某个属性,且该属性是基本类型,要写成函数式
监视响应式对象中的某个属性,且该属性是对象类型,可以直接写,也能写函数,更推荐写函数


⭐结论:监视的要是对象里的属性,那么最好写函数式
⭐注意点:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视。

基本类型属性的监视

当监视响应式对象中的基本类型属性时,推荐使用函数式的方式来访问该属性的值。这是因为基本类型的属性不会触发对象的重新分配,所以每次获取的都是最新的值。

示例:

import { watch, reactive } from 'vue';const person = reactive({ name: 'John' });// 使用函数式监视响应式对象中的 'name' 属性
watch(() => person.name,(newValue, oldValue) => {console.log(`变化前:${oldValue} 变化后:${newValue}`);}
);

在这个例子中,我们通过函数 () => person.name 来获取 person 对象的 name 属性的值。每次 watch 触发时,都会调用这个函数以确保获取到最新的 name 值。

对象类型属性的监视

当监视响应式对象中的对象类型属性时,可以直接写属性名,也可以使用函数式。推荐使用函数式,尤其是当你需要监视对象内部属性的变化时。

示例:

const person = reactive({ detail: { address: '123 Main St' } });// 使用函数式监视 'detail' 对象内部的 'address' 属性
watch(() => person.detail.address,(newValue, oldValue) => {console.log(`变化前: ${oldValue} 变化后:${newValue}`);},deep: true } // 开启深度监视,以追踪对象内部属性的变化
);

在这个例子中,我们监视的是 person.detail.address。由于 address 是 detail 对象的属性,我们需要开启深度监视 { deep: true } 来确保当 address 发生变化时,watch 能够触发。
我们通过函数 () => person.name 来获取 person 对象的 name 属性的值。每次 watch 触发时,都会调用这个函数以确保获取到最新的 name 值。

⭐情况五:监视上述的多个数据

示例

import { watch, reactive, ref } from 'vue';// 使用 reactive 创建一个响应式对象
const person = reactive({name: 'John',car: 'Toyota'
});// 使用 ref 创建一个响应式引用
const age = ref(30);// 监视 person 对象的 'name' 属性和 age 引用
watch([() => person.name, age], (newValues, oldValues) => {// newValues 和 oldValues 都是数组,分别包含新旧值console.log(`Name changed to ${newValues[0]}, Age changed to ${newValues[1]}`);// 如果只想监视 person.car 的变化,可以这样写:// watch([() => person.car, age], callback, options)
}, { deep: true });

在这个例子中:

  • 使用 reactive 创建了一个响应式对象 person,它包含 name 和 car 属性。
  • 使用 ref 创建了一个响应式引用age。 使用 watch 来监视 person.name 和 age。
  • 这里通过传递一个数组给 watch的第一个参数来实现同时监视多个数据源。数组中的每个元素都是一个返回要监视数据的函数或响应式引用。
  • newValues 和oldValues 参数都是数组,它们包含了所有监视数据源的新旧值。数组中每个元素的顺序与 watch 第一个参数中的顺序相对应。
  • { deep: true } 表示对 person 对象进行深度监视,这样可以确保当对象内部的属性变化时,也能触发 watch
    的回调函数。

注意事项

  • 当监视多个响应式数据源时,确保 newValues 和 oldValues 的索引与 watch 第一个参数中数据源的顺序相匹配。
  • 使用deep: true 选项可以确保当监视的对象或数组内部发生变化时,也能触发回调函数。

五、watchEffect

watchEffect 是 Vue 3 的一个工具,它用来观察你的数据。当你的数据变化时,它会做一些事情。

使用方法

  1. 选择数据:首先,你需要有一些数据,比如一个数字。
  2. 告诉 watchEffect 观察这个数据。
  3. 决定数据变化时要做的事情:当这个数据变化时,watchEffect 会帮你执行一个操作,比如打印信息。

示例

// 假设我们有一个数字,我们想观察它的变化
const count = 0;// 使用 `watchEffect` 观察 `count` 的变化
watchEffect(() => {// 当 `count` 变化时,打印 `count` 的新值console.log(`New value of count is: ${count}`);
});// 如果你改变了 `count` 的值,上面的打印就会执行

停止观察

如果你后面不想观察了,可以告诉 watchEffect 停止。

const stop = watchEffect(() => {// 逻辑
});// 想要停止观察时,调用这个函数
stop();

这篇关于Vue 3响应式系统全解析:深入ref、reactive、computed、watch及watchEffect的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/930883

相关文章

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

Java Stream流使用案例深入详解

《JavaStream流使用案例深入详解》:本文主要介绍JavaStream流使用案例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录前言1. Lambda1.1 语法1.2 没参数只有一条语句或者多条语句1.3 一个参数只有一条语句或者多

Golang HashMap实现原理解析

《GolangHashMap实现原理解析》HashMap是一种基于哈希表实现的键值对存储结构,它通过哈希函数将键映射到数组的索引位置,支持高效的插入、查找和删除操作,:本文主要介绍GolangH... 目录HashMap是一种基于哈希表实现的键值对存储结构,它通过哈希函数将键映射到数组的索引位置,支持

Python使用getopt处理命令行参数示例解析(最佳实践)

《Python使用getopt处理命令行参数示例解析(最佳实践)》getopt模块是Python标准库中一个简单但强大的命令行参数处理工具,它特别适合那些需要快速实现基本命令行参数解析的场景,或者需要... 目录为什么需要处理命令行参数?getopt模块基础实际应用示例与其他参数处理方式的比较常见问http

Python利用ElementTree实现快速解析XML文件

《Python利用ElementTree实现快速解析XML文件》ElementTree是Python标准库的一部分,而且是Python标准库中用于解析和操作XML数据的模块,下面小编就来和大家详细讲讲... 目录一、XML文件解析到底有多重要二、ElementTree快速入门1. 加载XML的两种方式2.

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

java解析jwt中的payload的用法

《java解析jwt中的payload的用法》:本文主要介绍java解析jwt中的payload的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java解析jwt中的payload1. 使用 jjwt 库步骤 1:添加依赖步骤 2:解析 JWT2. 使用 N

Python中__init__方法使用的深度解析

《Python中__init__方法使用的深度解析》在Python的面向对象编程(OOP)体系中,__init__方法如同建造房屋时的奠基仪式——它定义了对象诞生时的初始状态,下面我们就来深入了解下_... 目录一、__init__的基因图谱二、初始化过程的魔法时刻继承链中的初始化顺序self参数的奥秘默认

HTML5中的Microdata与历史记录管理详解

《HTML5中的Microdata与历史记录管理详解》Microdata作为HTML5新增的一个特性,它允许开发者在HTML文档中添加更多的语义信息,以便于搜索引擎和浏览器更好地理解页面内容,本文将探... 目录html5中的Mijscrodata与历史记录管理背景简介html5中的Microdata使用M

html5的响应式布局的方法示例详解

《html5的响应式布局的方法示例详解》:本文主要介绍了HTML5中使用媒体查询和Flexbox进行响应式布局的方法,简要介绍了CSSGrid布局的基础知识和如何实现自动换行的网格布局,详细内容请阅读本文,希望能对你有所帮助... 一 使用媒体查询响应式布局        使用的参数@media这是常用的