vue3 响应式 API:ref() 和 reactive()

在 Vue 3 中,响应式系统是其核心特性之一,它使得数据的变化能够自动触发视图的更新。

官方文档:
响应式 API:核心
要更好地了解响应式 API,推荐阅读官方指南中的章节:
响应式基础 (with the API preference set to Composition API)
深入响应式系统

reactive()

基本概念

  • 作用:用于创建一个响应式的对象。如果对这个对象的属性进行修改,会自动触发视图的更新。
  • 可接收的数据类型:只能定义对象类型的响应式数据。使用reactive()定义基本类型会报错,要用ref
  • 语法let 响应式对象= reactive(源对象)
  • 返回值:一个Proxy的实例对象,简称:响应式对象
  • 类型
function reactive<T extends object>(target: T): UnwrapNestedRefs<T>

使用reactive()创建对象类型的响应式数据:

<template><div><p>姓名: {{ person.name }}</p><p>年龄: {{ person.age }}</p></div>
</template>
<script setup lang="ts">
import { reactive } from 'vue';const person = reactive({name: '张三',age: 36
})
console.log(person)// 报错:类型“number”的参数不能赋给类型“object”的参数。
let count = reactive(0)</script>

控制台打印:
在这里插入图片描述

直接修改响应式对象的属性值,会触发依赖这些属性的组件重新渲染:

// 直接修改,立即响应
person.name = '李四'
person.age = 24// 使用方法,调用方法后再响应
const changePerson = () => {person.name = '李四'person.age = 24
}

reactive()深层响应性

  • 对象的嵌套属性也具有响应式
    • 响应式转换是“深层”的:它会影响到所有嵌套的属性。一个响应式对象也将深层地解包任何 ref 属性,同时保持响应性。
<template><div><p>b: {{ obj.a.b }}</p><p>d: {{ obj.a.c.d }}</p><button @click="changeB">修改b</button><button @click="changeD">修改d</button></div>
</template>
<script setup lang="ts">
import { reactive } from 'vue';const obj = reactive({a: {b: 10,c: {d: 20}},
});
const changeB = () => {obj.a.b++
}
const changeD = () => {obj.a.c.d++
}
</script>

在这个例子中,修改嵌套对象的属性也会触发响应式更新。
不管数据嵌套的有多深,reactive()一定会把数据变成响应式的。

  • 数组的响应式
    • 对响应式数组进行添加、删除、修改等操作都会触发依赖这个数组的组件重新渲染。
<template><div><ul><li v-for="item in personArr" :key="item.id">姓名:{{ item.name }} , 年龄:{{ item.age }} 岁</li></ul><button @click="addPerson">添加</button></div>
</template>
<script setup lang="ts">
import { reactive } from 'vue';const personArr = reactive([{id: 1, name: '张三', age: 17 },{id: 2, name: '李四', age: 18 },{id: 3, name: '王二', age: 16 },
]);console.log(personArr); 
const addPerson = () => {personArr.push({ id: 4, name: '张麻子', age: 16 });
};</script>

控制台打印:
在这里插入图片描述

  • 直接赋值整个响应式对象不会触发响应式更新
let person = reactive({name: '张三',age: 36,
});// 这样不会触发响应式更新
const changePerson = () => {person = {name: 'john',age: 30}
}// 使用Object.assign()等方法来更新属性
const changePerson = () => {Object.assign(person, {name: '李四',age: 24,});
}
  • 响应式对象的属性必须在创建时存在
const person = reactive({name: '王二',
});// 报错:类型“{ name: string; }”上不存在属性“age”。
person.age = 30;  

ref()

基本概念

ref()接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的属性 .value

  • 作用:定义响应式的变量。
  • 可接收的数据类型:基本类型、对象类型的响应式数据。若ref接收的是对象类型,内部其实也是调用了reactive函数。
  • 语法let xxx = ref(初始值)。
  • 返回值:一个RefImpl的实例对象,简称ref对象或refref对象的value属性是响应式的。
  • 类型
function ref<T>(value: T): Ref<UnwrapRef<T>>interface Ref<T> {value: T
}

ref 对象是可更改的,也就是说可以为 .value 赋予新的值。它也是响应式的,即所有对 .value 的操作都将被追踪。

使用 ref() 创建基本类型的响应式数据

<template><div><p>count: {{ count  }}</p></div>
</template>
<script setup lang="ts">
import { ref } from 'vue'// 在组合式 API 中,推荐使用 ref() 函数来声明响应式状态
const count = ref(0)
consoe.log(count)    // count 是一个RefImpl的实例对象
console.log('count.value:', count.value) // count.value:0count.value = 1
console.log('count.value:', count.value) // count.value:1
</script>

控制台打印:
在这里插入图片描述
注意:

  • JS中操作数据需要:xxx.value,但模板中不需要.value,直接使用{{xxx}}
  • 对于const count = ref(0)来说,count不是响应式的,count.value是响应式的。

ref()深层响应性

ref()包裹的是一个对象时,对这个对象的属性进行修改也会触发响应式更新。

<template><div><p>姓名: {{ person.name }}</p><p>年龄: {{ person.age }}</p><button @click="changePerson">修改信息</button></div>
</template>
<script setup lang="ts">
import { ref } from 'vue';const person = ref({name: '张三',age: 36
})
console.log(person)const changePerson = () => {person.name = '李四'person.age = 24
}
</script>

使用ref()定义一个对象类型的响应式数据,页面是正常展示数据的:
在这里插入图片描述
数据详细信息解析:

  • RefImpl {... }:这表示这是一个由ref函数创建的响应式对象的内部实现结构展示。
  • __v_isShallow:表示是否是浅层响应式,这里为false,说明不是浅层响应式。
  • dep:这是一个依赖收集器,用于跟踪哪些部分的代码依赖于这个响应式对象。当响应式对象的值发生变化时,会通知依赖它的部分进行更新。这里显示为一个包含一个ReactiveEffectMap,说明有一个依赖项。
  • __v_isRef:为true,表明这是一个由ref创建的响应式引用。
  • _rawValue:存储了原始的值,这里是一个包含nameage属性的对象。
  • _valuevalue:都是代理对象,通过代理可以实现对原始对象的响应式追踪。
  • [[Handler]][[Target]]:是与代理对象相关的内部属性,[[Handler]]是处理程序,用于定义对目标对象的各种操作的拦截行为,[[Target]]是被代理的原始对象。

从控制台打印的数据结构可以看出:如果将一个对象赋值给 ref,那么这个对象将通过 reactive() 转为具有深层次响应式的对象。

表面上它返回来的是一个RefImpl的实例对象,但是在这个实例对象的_valuevalue属性里,是 reactive() 的返回值:一个Proxy的实例对象。

直接调用changePerson修改信息,person没有被修改。编译器会报错:

const changePerson = () => {// 报错:类型“Ref<{ name: string; age: number; }>”上不存在属性“name”。person.name = '李四'// 报错:类型“Ref<{ name: string; age: number; }>”上不存在属性“age”。person.age = 24console.log(person)
}

ref定义的数据,如果要修改,要用.value来更改。

const changePerson = () => {console.log('修改前打印person.value:', person.value)person.value.name = '李四'person.value.age = 24console.log(person)
}

在这里插入图片描述

可以使用Vue - Official插件自动添加.value

在这里插入图片描述

在这里插入图片描述

ref()reactive()的区别

  1. 从数据类型看
    • ref()用来定义:基本类型数据对象类型数据
    • reactive()用来定义:对象类型数据
  2. 返回值类型
    • ref()返回值: 一个RefImpl的实例对象。
    • reactive()返回值:一个Proxy的实例对象,简称:响应式对象。
  3. 响应式更新方式
  • ref()通过修改.value属性来触发响应式更新。
    ref()跳过 .value属性直接修改变量的值,不会出发响应式更新。
import { ref } from 'vue';
let person = ref({name: '张三', age: 36});
const changePerson = () => {// 重新分配一个对象,触发响应式更新person.value = { name: '李四', age: 24 }// ref 跳过 .value,不会出发响应式更新person = { name: '李四', age: 24 }
}let count = ref(0)
const changeCount = () => {// 可以触发响应式更新count.value ++;// 不会触发响应式更新count = ref(10)
}
  • reactive()直接修改对象的属性即可触发响应式更新。
import { reactive } from 'vue';
let person = reactive({name: '张三', age: 36});
const changePerson = () => {person.name = '李四'   // 触发响应式更新person.age = 30        // 触发响应式更新
}
  • reactive()重新分配一个新对象,会失去响应式(可以使用Object.assign去整体替换)。
import { reactive } from 'vue';
let person = reactive({name: '张三', age: 36});// 不会触发响应式更新
const changePerson = () => {// 重新分配一个对象person = { name: '李四', age: 24 }// person = reactive({name: '张三', age: 36});// 与person = reactive({ name: '李四',age: 24 });// 是完全不同的2个完全不同的person, 根本不是同一个东西person = reactive({ name: '李四', age: 24 });
}// 使用Object.assign()等方法来更新属性
const changePerson = () => {Object.assign(person, {name: '李四',age: 24,});
}
  1. 深层响应性

    • reactive()可以自动保持对象的深层响应性,即嵌套对象的属性修改也会触发响应式更新。
    • 对于ref()包裹的对象,直接修改嵌套对象的属性可能不会触发响应式更新,需要特殊处理。
  2. 使用场景

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/877410.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SX_初识GitLab_1

1、对GitLab的理解&#xff1a; 目前对GitLab的理解是其本质是一个远程代码托管平台&#xff0c;上面托管多个项目&#xff0c;每个项目都有一个master主分支和若干其他分支&#xff0c;远程代码能下载到本机&#xff0c;本机代码也能上传到远程平台 1.分支的作用&#xff1a…

Oracle大师Roger Cornejo的推荐:使用ASH诊断Oracle解析故障

这篇文章被Oracle大师Roger Cornejo在X平台上推荐&#xff08;见下图&#xff09;&#xff0c;英文原文在&#xff1a; Diagnosing Parsing Issue with ASH 解析&#xff0c;尤其是硬解析&#xff0c;是非生产性操作&#xff0c;会消耗大量系统资源&#xff0c;导致库缓存争用…

Meta 如何实现 99.99999999% 的缓存一致性

曾经的故事 Meta&#xff08;Facebook&#xff09; 曾经运行一个简单的技术栈——PHP 和 MySQL。 但随着更多用户的加入&#xff0c;他们面临着可扩展性问题。因此他们建立了一个分布式缓存。 虽然这暂时解决了可扩展性问题&#xff0c;但保持缓存数据的新鲜度变得困难。以下…

SpringBoot 整合 Redis 实现验证码登录功能

一、整合Redis 在pom.xml中添加Redis相关依赖&#xff1b; <!--Spring Data Redis依赖配置--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency>…

阿里云账户注册与实名认证详细教程

在开始使用阿里云服务之前&#xff0c;您需要先有一个阿里云账号&#xff0c;拥有阿里云账号后&#xff0c;您可以选购和使用云产品和服务。如果您没有阿里云账号&#xff0c;需要先注册一个阿里云账号。 说明 一个手机号码下最多可以注册6个阿里云账号。如果您的手机号码已经…

一分钟了解VMware虚拟机三种网络模式区别

VMware虚拟机提供了三种主要的网络模式&#xff0c;分别是桥接模式&#xff08;Bridged Mode&#xff09;、网络地址转换模式&#xff08;NAT Mode&#xff09;和仅主机模式&#xff08;Host-Only Mode&#xff09;。这三种模式各有其特点和适用场景&#xff0c;以下是对它们之…

Perfectly Clear WorkBench中文绿色版,让每一张照片都完美无瑕

软件简介 你是否曾经为了一张不完美的照片而感到遗憾&#xff1f;是否曾经因为照片中的小瑕疵而不得不花费大量时间进行后期处理&#xff1f;现在&#xff0c;有了Perfectly Clear WorkBench&#xff0c;这些问题都将迎刃而解。作为全球领先的智能图像校正技术商推出的图像清晰…

jvm实战

一、查看JVM内存使用状况 jps 查看本地正在运行的java进程和进程ID(pid) win10报jps不是内部或外部命令,也不是可运行的程序或批处理文件解决?将用户变量和系统变量的Path都追加2个bin。 jinfo jinfo pid 查看指定pid的所有JVM信息jinfo -flags pid 查询虚拟机运行参数…

低代码开发平台:加速企业数字化转型的利器

前言 在软件开发领域&#xff0c;传统的编码方式往往复杂且耗时&#xff0c;对技术团队的技能要求高。随着企业数字化转型的加速&#xff0c;低代码开发平台作为一种新兴的解决方案&#xff0c;逐渐成为许多组织提升开发效率、降低技术门槛的利器。本文将深入探讨低代码开发的…

【Drools】(三)基于业务数据动态调用 DRL 规则文件:详细实现与测试指南

基于业务数据动态调用 DRL 规则文件&#xff1a;详解与实战 在业务规则管理中&#xff0c;DRL 文件&#xff08;Drools Rule Language 文件&#xff09;用于定义和执行业务规则。通过动态调用 DRL 文件&#xff0c;我们可以根据不同的业务场景灵活配置和执行定制化的规则&…

【中项】系统集成项目管理工程师-第8章 信息安全工程-8.3工程体系架构

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&…

MongoDB 基础知识

一、为什么学习MongoDB MongoDB解决Mysql 的“三高”问题&#xff1a; 1.对数据库高并发写入需求 2.对海量数据高效率存储访问需求 3.对数据库高扩展和高可用的需求 MongoDB 实际应用&#xff1a; 1.社交场景&#xff0c;比如朋友圈&#xff0c;附近的人的地点的存储 2.…

Python for循环迭代原理(迭代器 Iterator)

在使用Python时&#xff0c;我们经常会使用for循环来访问容器对象&#xff08;列表、字符、字典等&#xff09;中的元素。其幕后实际是通过迭代协议来完成的&#xff0c;迭代是一种依次访问对象中元素的方式&#xff0c;for循环在对象上调用iter()函数生成一个迭代器&#xff0…

【Docker】Namespace 空间隔离实战

一、实战目的 了解隔离能力并不是 Docker 提供的&#xff0c;而是操作系统内核提供基本能力。 二、基础知识 1、dd 命令详解 Linux dd 命令用于读取、转换并输出数据。 dd 可从标准输入或文件中读取数据&#xff0c;根据指定的格式来转换数据&#xff0c;再输出到文件、…

Vue3----扩展 element Plug card

扩展 element Plug card 增加全屏&#xff0c;折叠操作项 核心代码 <template><div class"cc-card-component"><el-card v-if"state.isShow" :class"state.class" :bodyStyle"bodyStyle" :shadow"props.shadow…

Vmwar保姆级安装与配置

文章目录 一、官方下载1.访问VMware官方网站&#xff1a;2.选择产品&#xff1a;3.下载安装包&#xff1a; 二、VMware的安装1.运行安装程序2.选择安装位置3.选择安装选项4.完成安装 三、启动VMware Workstation Pro并配置虚拟机1.创建新的虚拟机&#xff1a;2.配置虚拟机硬件 …

【C#】.net core 6.0 webapi 使用core版本的NPOI的Excel读取数据以及保存数据

欢迎来到《小5讲堂》 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 背景读取并保存NPOI信息NPOI 插件介绍基本功能示例代码写入 Excel 文件…

前端JavaScript处理小数精度问题(最佳实践)

前言&#xff1a; 针对于小数精度问题&#xff0c;本次我们主要推荐两种方式&#xff0c;一种是简单的函数封装&#xff0c;一种是使用第三方库big.js。 方法一&#xff1a; 自封装函数搭配parseFloat和toFixed解决小数精度问题&#xff0c;仅适用于解决一般性小数精度问题&…

【云原生】Kubernetes----k8s免密使用harbor私有仓库

目录 引言 一、搭建Harbor仓库 &#xff08;一&#xff09;关闭防护 &#xff08;二&#xff09;安装docker &#xff08;三&#xff09;安装docker-compose &#xff08;四&#xff09;安装harbor-offline 1.获取安装包 2.修改配置文件 3.启动服务 4.登录仓库验证 二…

营销人看巴黎奥运会,看到了什么?

不同的人眼中的巴黎奥运会是不一样的&#xff1a;环保人士关注奥运场馆的绿色设计&#xff0c;以及赛事期间对可再生能源的利用&#xff1b;旅游博主用镜头捕捉巴黎奥运会每一个精彩瞬间&#xff1b;社会学家在巴黎奥运会看到多元文化的交流与融合…… 那么营销人在巴黎奥运会…