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

相关文章

Java图片压缩三种高效压缩方案详细解析

《Java图片压缩三种高效压缩方案详细解析》图片压缩通常涉及减少图片的尺寸缩放、调整图片的质量(针对JPEG、PNG等)、使用特定的算法来减少图片的数据量等,:本文主要介绍Java图片压缩三种高效... 目录一、基于OpenCV的智能尺寸压缩技术亮点:适用场景:二、JPEG质量参数压缩关键技术:压缩效果对比

关于WebSocket协议状态码解析

《关于WebSocket协议状态码解析》:本文主要介绍关于WebSocket协议状态码的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录WebSocket协议状态码解析1. 引言2. WebSocket协议状态码概述3. WebSocket协议状态码详解3

CSS Padding 和 Margin 区别全解析

《CSSPadding和Margin区别全解析》CSS中的padding和margin是两个非常基础且重要的属性,它们用于控制元素周围的空白区域,本文将详细介绍padding和... 目录css Padding 和 Margin 全解析1. Padding: 内边距2. Margin: 外边距3. Padd

CSS will-change 属性示例详解

《CSSwill-change属性示例详解》will-change是一个CSS属性,用于告诉浏览器某个元素在未来可能会发生哪些变化,本文给大家介绍CSSwill-change属性详解,感... will-change 是一个 css 属性,用于告诉浏览器某个元素在未来可能会发生哪些变化。这可以帮助浏览器优化

CSS去除a标签的下划线的几种方法

《CSS去除a标签的下划线的几种方法》本文给大家分享在CSS中,去除a标签(超链接)的下划线的几种方法,本文给大家介绍的非常详细,感兴趣的朋友一起看看吧... 在 css 中,去除a标签(超链接)的下划线主要有以下几种方法:使用text-decoration属性通用选择器设置:使用a标签选择器,将tex

Oracle数据库常见字段类型大全以及超详细解析

《Oracle数据库常见字段类型大全以及超详细解析》在Oracle数据库中查询特定表的字段个数通常需要使用SQL语句来完成,:本文主要介绍Oracle数据库常见字段类型大全以及超详细解析,文中通过... 目录前言一、字符类型(Character)1、CHAR:定长字符数据类型2、VARCHAR2:变长字符数

前端高级CSS用法示例详解

《前端高级CSS用法示例详解》在前端开发中,CSS(层叠样式表)不仅是用来控制网页的外观和布局,更是实现复杂交互和动态效果的关键技术之一,随着前端技术的不断发展,CSS的用法也日益丰富和高级,本文将深... 前端高级css用法在前端开发中,CSS(层叠样式表)不仅是用来控制网页的外观和布局,更是实现复杂交

Python将博客内容html导出为Markdown格式

《Python将博客内容html导出为Markdown格式》Python将博客内容html导出为Markdown格式,通过博客url地址抓取文章,分析并提取出文章标题和内容,将内容构建成html,再转... 目录一、为什么要搞?二、准备如何搞?三、说搞咱就搞!抓取文章提取内容构建html转存markdown

在React中引入Tailwind CSS的完整指南

《在React中引入TailwindCSS的完整指南》在现代前端开发中,使用UI库可以显著提高开发效率,TailwindCSS是一个功能类优先的CSS框架,本文将详细介绍如何在Reac... 目录前言一、Tailwind css 简介二、创建 React 项目使用 Create React App 创建项目

vue使用docxtemplater导出word

《vue使用docxtemplater导出word》docxtemplater是一种邮件合并工具,以编程方式使用并处理条件、循环,并且可以扩展以插入任何内容,下面我们来看看如何使用docxtempl... 目录docxtemplatervue使用docxtemplater导出word安装常用语法 封装导出方