第七节:带你全面理解vue3: 其他响应式进阶API

news/2024/7/20 18:17:58/文章来源:https://blog.csdn.net/fjiex/article/details/139181457

前言:

针对vue3官网中, 响应式:进阶API 中, 我们在上一章中给大家讲解了shallowRef, shallowReactive, shallowReadonly几个API的使用.

本章主要对剩下的API 进行讲解, 我们先看一下官网中进阶API 都有那些

img

对于剩下这些API, 你需要了解他们创建目的, 是为了解决之前的API存在的那些痛点问题, 这样你就能更好的了解使用他们的细节.工作中就可以有的放矢的选择不同的API.

1. triggerRef

我们首先来分析一下triggerRefAPI 的使用

1.1. triggerRef 针对的痛点问题

我们先看一个痛点问题:

对于ref响应式数据的变化, vue帮我们处理副作用. 比如,页面的更新, watchEffect侦听器回调函数的调用等.

但对于浅层响应数据, 比如shallowRef创建的数据, 其深层并不具有响应性, 也就是说vue并没有监测这些数据的变化, 当对深层数据进行修改时, 并不会触发副作用, 比如页面不会自动刷新.

triggerRefAPI 就是为了解决shallowRef浅层响应式数据深层修改问题.

当深层修改时, 会强制触发依赖于一个浅层 ref 的副作用,这通常在对浅引用的内部值进行深度变更后使用。

1.2. triggerRef 类型

类型:

function triggerRef(ref: ShallowRef): void

triggerRefAPI 函数接收一个shallowRefAPI 创建的数据, 作用就是强制触发这个浅层ref数据的副作用.

1.3. triggerRef 使用示例

示例:

<template><div><h3>shallowReadonly</h3><div>{{ count }}</div><div>{{ count2 }}</div><button @click="change">修改数据源</button></div>
</template><script lang="ts">
import { defineComponent, readonly, ref, shallowReadonly, shallowRef, triggerRef, watchEffect } from 'vue'export default defineComponent({setup() {const count = ref({ num: 0 })const count2 = shallowRef({ num: 0 })// 对于ref 数据, 是深层响应式,// 因此当我们通过count.value.num++ 修改数据时,依然会触发watchEffect副作用函数watchEffect(() => {console.log('count.value.num', count.value.num)})// 因为shallowRef 数据不是深层响应式, 只有.value 整体修改才会触发响应式// 因为当我们通过count2.value.num++ 修改数据时,不会出发watchEffect 副作用函数// 同时视图也不会发生更改watchEffect(() => {console.log('count2.value.num', count2.value.num)})// 修改数据const change = () => {// count.value.num++count2.value.num++// 如果希望shallowRef 深层数据修改后,触发视图更新// 那么就需要使用triggerRef 手动触发更新triggerRef(count2)  // 手动更新count2}return { count, count2, change }}
})
</script>

通过示例的运行结果, 你也可以看出. shallowRef创建响应式数据, 在深层数据发生变化时, 不会触发页面更新 和watchEffect的处理函数. 因为深层不具有响应性.

当我们手动调用triggerRef函数, 并将shallowRef创建数据作为参数, 就是告诉vue , 我们需要强制执行shallowRef数据的副作用. 此时页面将会更新, watchEffect处理函数也会自动执行

1.4. triggerRef 使用小结

在理解triggerRefAPI 的使用后, 针对该API, 我做了以下小结

  • triggerRef常与shallowRef搭配使用
  • triggerRef会强制更新以shallowRef数据作为依赖的副作用,ref数据会自动触发这些副作用

我们需要注意的是: vue3只提供了triggerRef这个方法,但没有提供triggerReactive的方法。 也就是说triggerRef 【不可以】去更改 shallowReactive创建的数据

2. toRaw

根据一个 Vue 创建的代理返回其原始对象

2.1. toRaw 针对的问题

vue3中, 我们通过 reactive()readonly()shallowReactive() shallowReadonly()四个API 创建的响应式数据, 本质上就是通过Proxy创建的代理对象.

但有时我们在做数据传输时, 我们并不需要传响应式数据, 我们只想传最基本的原始对象.

toRawAPI 的作用就是返回 reactive()readonly()shallowReactive(),shallowReadonly() 创建的代理对应的原始对象。

2.2. toRaw 类型

toRaw 函数签名

function toRaw<T>(proxy: T): T

toRawAPI 函数接收一个Proxy代理对象(响应式对象)作为参数,

2.3. toRaw 使用示例

示例:

<template><div><h3>shallowReactive</h3><div>{{ user }}</div><button @click="change">修改数据源</button></div>
</template><script lang="ts">
import { defineComponent, reactive, toRaw } from 'vue'export default defineComponent({setup() {// 代理目标对象const obj = { name: '张三', age: 18 }// reactive 处理的代理对象const user = reactive(obj)// 控制触发代理对象console.log('user', user)// 使用toRaw, 参数是代理对象, 返回代理对象的目标对象console.log('toRaw(user)', toRaw(user))console.log('toRaw(user) === obj', toRaw(user) === obj)  // true// 修改数据const change = () => {user.name = '李四'}return { user, change }}
})
</script>

通过控制台输出结果, 你可以看出, toRaw 就是获取代理对象的原目标对象.

这是一个可以用于临时读取而不引起代理访问/跟踪开销,或是写入而不触发更改的特殊方法。不建议保存对原始对象的持久引用,请谨慎使用。

这句话来自于官网, 这句话你可以这么理解,

代理对象具有响应性, 可以理解为vue在监测这个数据的变化, 这个监测会消耗性能. 如果你的操作不要触发副作用, 就没有必要 使用具有响应性的代理对象.

比如调用接口时传入的参数, 就可以使用toRaw去掉代理对象的外壳, 获取到原始对象传入接口.

3. markRaw

markRaw 函数的作用就是将一个对象转为不可代理对象.

如果使用reactiveAPI , 也不会代理markRaw函数返回的对象, 会直接返回原对象.

示例:

<template><div><h3>shallowReactive</h3><div>{{ user }}</div><button @click="change">修改数据源</button></div>
</template><script lang="ts">
import { defineComponent, markRaw, reactive } from 'vue'export default defineComponent({setup() {// 代理目标对象const obj = { name: '张三', age: 18 }// 将obj原始对象标记为不可代理const markObj = markRaw(obj)// reactive 处理的代理对象const user = reactive(markObj)// user 不是代理对象console.log('user', user)// 修改数据const change = () => {user.name = '李四'}return { user, change }}
})
</script>

控制台输出:

img

通过控制台输出结果, 可以看出, 通过markRaw 处理过的对象具有一个__v_skip的属性, 用于标记这个对象不能创建代理对象, 即响应式数据.

尽管你将该对象传入reactive, 返回的也不是一个代理对象, 而是原对象.

既然不是响应数据,修改user.name 时, 就不会触发视图更新

该API的作用就是, 帮助你给一些你不希望创建为代理对象的原始对象添加标记.

4. effectScope

4.1. effectScope 作用

vue3的使用过程中,我们可能会针对同一个响应式数据创建多个副作用.比如computed, watch, watchEffect等.

再次过程中, 如果关闭某个副作用, 比如watch创建的侦听器, 就需要通过返回值关闭. 那么多个副作用你就需要一个一个关闭. 使用相对麻烦

effectScope字面意思就是副作用作用域, 可以理解为, 该函数创建一个作用域, 将所有的副作用放在共同一个作用域中, 如果以后想统一关闭副作用, 就可以使用作用域整体关闭.

4.2. effectScope

类型

function effectScope(detached?: boolean): EffectScopeinterface EffectScope {run<T>(fn: () => T): T | undefined // 如果作用域不活跃就为 undefinedstop(): void
}

effectScope函数返回一个作用域对象, 即EffectScope类型.

该作用域对象上具有run, stop方法, 同时run方法接收一个回调函数作为参数.

4.3. effectScope 使用方式

通过effectScope函数创建一个 effect 作用域,可以捕获其中所创建的响应式副作用 (即计算属性和侦听器),这样捕获到的副作用可以一起处理。

示例:

<template><div><h3>shallowReactive</h3><div>{{ count }}</div><button @click="change">修改数据源</button></div>
</template><script lang="ts">
import { computed, defineComponent, effectScope, markRaw, reactive, ref, shallowReactive, toRaw, watch, watchEffect } from 'vue'export default defineComponent({setup() {// 创建ref 数据const count = ref(10)// 创建副作用作用域const scope = effectScope()// 控制台输出 effect 作用域console.log("scope", scope);// 收集运行的副作用scope.run(() => {// 计算属性副作用const computedCount = computed(() => count.value * 2)// watch 侦听副作用watch(count,() => {console.log('computedCount', computedCount.value)console.log('watch count', count.value)})// watchEffect 副作用watchEffect(() => {console.log('watchEffect count', count.value)})})console.log('scope', scope) // 2秒以后关闭所有的副作用setTimeout(() => {scope.stop()}, 2000)// 修改数据const change = () => {count.value++}return { count, change }}
})
</script>

控制台输出结果:

img

通过控制台输出的effect作用域对象, 你可以看到, 作用域将回调函数中的副作用进行了收集, 存储在effects属性上.

同时effect作用域对象原型对象上具有run收集副作用的方法, stop关闭副作用的方法.

5. getCurrentScope

getCurrentScope函数返回当前活跃的 effect 作用域。

在前一个API中, 给大家讲解了effectScope函数, 该函数执行后会返回一个effect 作用域, 通过调用effect作用域对象的run方法收集所有副作用. 我们就可以在run方法的回调函数中, 通过getCurrentScope函数获取到正在活跃的effect作用域对象.

示例:

// 创建副作用作用域
const scope = effectScope();
console.log("scope", scope);// 收集运行的副作用
scope.run(() => {// 计算属性副作用const computedCount = computed(() => count.value * 2);// watch 侦听副作用watch(count, () => {console.log("computedCount", computedCount.value);console.log("watch count", count.value);});// watchEffect 副作用watchEffect(() => {console.log("watchEffect count", count.value);});// 通过  getCurrentScope() 获取当前真正活跃的 effect 作用域对象const effectScope = getCurrentScope();console.log("getCurrentScope", effectScope === scope);// 控制台输出结果: getCurrentScope true
});

示例中, 我们通过effectScope创建了一个effect作用域对象, 当调用该作用域对象的run方法,传入回调函数, 会自动执行回调函数, 收集副作用, 并将收集到的副作用保存在副作用effect作用域中. 也就是说, 在执行回调函数时, 我们创建的scope就是活跃的effect作用域

之后,我们通过执行getCurrentScope函数获取当前活跃的副作用作用域, 和之前我们创建的作用域对比, 发现getCurrentScope 获取的就是我们创建的effect作用域.

其实每一个组件都有一个effect作用域, 用于收集组件内所有的副作用. 组件更新函数本身也就是一个副作用. 这也就是响应式数据变化后, 页面会重新渲染的原因.

以及组件被销毁后, vue3 会通过组件的effect作用域清理组件内收集的所有副作用

该API 在工作中并不常使用到. 甚至一个项目里连一次都不会用到.

6. onScopeDispose

该API 函数主要用于调试, 工作中也不怎么常用, 其作用就是在当前活跃的副作用(effect)作用域对象上注册一个调试的回调函数. 在effect作用域关闭时, 会自动调用注册的回调函数,.

示例:

// 创建副作用作用域
const scope = effectScope();
console.log("scope", scope);// 收集运行的副作用
scope.run(() => {// 计算属性副作用const computedCount = computed(() => count.value * 2);// watch 侦听副作用watch(count, () => {console.log("computedCount", computedCount.value);console.log("watch count", count.value);});// watchEffect 副作用watchEffect(() => {console.log("watchEffect count", count.value);});// 在当前活跃的 effect 作用域对象上注册一个回调函数onScopeDispose(() => {console.log("当前effectScope 停止");});
});// 2秒以后关闭所有的副作用
setTimeout(() => {scope.stop();
}, 2000);

示例中, 我们在effectScope收集副作用时, 通过onScopeDispose函数注册了一个回调函数.

effectScope副作用作用域, 即scope对象调用stop方法时, 会自动执行注册的回调函数. 多用于功能调试

7. 结语

至此, 就把vue3中响应式进阶API 中剩余的API函数给大家讲完了, 这里比较常用的API 有triggerRef, toRaw, markRaw, effectScope, 其余两个API 函数并不怎么常用.

这里尤其要注意effectScope, 使用好了可以给代码增色不少.

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

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

相关文章

Android 生成正式版密钥库 KeyStore

步骤1&#xff1a;打开生成正式版密钥库设置 点击 Build 菜单&#xff0c;选择 Generate Signed App Bundle or APK&#xff1a; 这是打开后的样子&#xff1a; 步骤2&#xff1a;选择 APK Android App Bundle 是用于上架 Google Play 商店的。 正常情况下选择 APK。 选择…

总是不能盈利?试着用这两个观点去学习现货白银的技巧

一进入现货白银市场&#xff0c;投资者都想着如何去找到现货白银交易的机会&#xff0c;学习现货白银投资的方法。其实这些都是手段&#xff0c;而最终的目的还是为我们的盈利服务。而对于盈利来说&#xff0c;其实胜率和风险报酬比才是影响盈利的重要因素&#xff0c;我们带着…

设计软件有哪些?建模和造型工具篇(4),渲染100邀请码1a12

建模使用到的工具有很多&#xff0c;这次我们接着介绍。 1、PolyBoost PolyBoost是由Digimation公司开发的3ds Max插件&#xff0c;旨在增强软件的多边形建模功能。该插件提供了一系列强大的建模工具&#xff0c;如边缘控制、顶点编辑、面片调整等&#xff0c;使用户能够更加…

短视频脚本创作的五个方法 沈阳短视频剪辑培训

说起脚本&#xff0c;我们大概都听过影视剧脚本、剧本&#xff0c;偶尔可能在某些综艺节目里听过台本。其中剧本是影视剧拍摄的大纲&#xff0c;用来指导影视剧剧情的走向和发展&#xff0c;而台本则是综艺节目流程走向的指导大纲。 那么&#xff0c;短视频脚本是什么&#xf…

每日一题《leetcode--59.螺旋矩阵 》

https://leetcode.cn/problems/spiral-matrix-ii/ 这道题跟我昨天发布的那道题一模一样&#xff0c;只需要注意这个矩阵是n*n。 文章代码如下&#xff1a; int** generateMatrix(int n, int* returnSize, int** returnColumnSizes) {int** array (int**)malloc(sizeof(int*) *…

加密资产私钥安全完整手册(一) ,bitget钱包为例

比特币和以太坊等加密货币的兴起开创了数字金融的新时代&#xff0c;但也带来了独特的安全挑战。这些代表现实世界价值的数字资产已成为黑客和窃贼的主要目标。为了安全地应对这种情况&#xff0c;了解私钥的基本概念至关重要。 私钥是加密货币所有权和安全性的基石。它们相当于…

完成商品SPU管理页面

文章目录 1.引入前端界面1.将前端界面放到commodity下2.创建菜单3.进入前端项目&#xff0c;使用npm添加依赖1.根目录下输入2.报错 chromedriver2.27.2的问题3.点击链接下载压缩包&#xff0c;然后使用下面的命令安装4.再次安装 pubsub-js 成功5.在main.js中引入这个组件 4.修改…

真实故障分享,H3C ER3208G3-X路由器-双绞线一闪一停

六类非屏蔽双绞线 网线钳 如上图所示&#xff0c;2号线接到h3c路由器出现网线一闪一停&#xff0c;用对线器测试一到8芯能一一对应&#xff0c;无法上网。2号线接到h3c交换机能正常上网&#xff0c;难道是网线对568A 568B有要求&#xff1f; 解决方式&#xff1a;通过两端568…

本地开发正常 线上CI/CD构建项目过程报错文件未能正确引用

问题快照 原因分析&#xff1a; 一般遇到这样的错误就是 文件路径或者文件名称未能正确匹配 或者文件不存在 会报这样的错误 以为很好解决 但这次 都排查 了 就是 没发现原因 不管怎么说还是要感谢 GPT的能力(分析问题的能力) 先上图 当我看到 第四步的时候 我立马 去仓库里查…

大模型预训练结果到底是什么?

近日参加一个线下 AI 交流会议&#xff0c;会上有个非本行业的老师提问&#xff1a;“大家说的训练好的大模型到底是什么&#xff1f;是像 Word 软件一样可以直接使用的程序吗&#xff1f;” 这个问题看似简单&#xff0c;却一下把我问住了。的确&#xff0c;我们这些身处 AI 领…

POLARDB:新零售用户MySQL上云最佳选择

什么是云数据库POLARDB&#xff1f; POLARDB是阿里云自主研发的最新一代RDS关系型数据库&#xff0c;是特别针对互联网场景设计的Cloud-Native 云原生数据库。POLARDB for MySQL版本&#xff0c;在提供100%兼容MySQL5.6/8.0的关系型事务处理ACID特性之上&#xff0c;能够提供完…

算法之背包问题

可分的背包问题是可以用贪心法来解决&#xff0c;而0-1背包问题通常使用动态规划方法来解决。 可分背包问题&#xff1a; 在可分背包问题中&#xff0c;物品可以被分割&#xff0c;您可以取走物品的一部分以适应背包的容量。这里的关键是物品的价值密度&#xff0c;即单…

间接平差——以水准网平差为例 (python详细过程版)

目录 一、原理概述二、案例分析三、代码实现四、结果展示本文由CSDN点云侠原创,间接平差——以水准网平差为例 (python详细过程版),爬虫自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT生成的文章。 一、原理概述 间接平差的函数模型和随机模型…

py黑帽子学习笔记_scapy

简介 代码简洁&#xff1a;相比于前两个博客总结&#xff0c;很多socket操作&#xff0c;如果使用scapy仅需几行代码即可实现 获取邮箱身份凭证 编写基础嗅探器&#xff0c;脚本可显示任何收到的一个包的详细情况 直接运行 尝试监听邮件收发&#xff0c;监听指定端口&#x…

解密网络流量监控:优化IT运维的利器

引言&#xff1a; 在当今数字化时代&#xff0c;网络流量监控是维护网络稳定与业务连续性的关键。作为一名资深网络工程师&#xff0c;我将分享一些关于网络流量监控的重要知识&#xff0c;并探讨如何在IT运维中运用这一工具优化网络性能&#xff0c;确保业务的顺畅进行。 1. 网…

Biological Psychiatry:内源性功能连接的特定模式与强迫症的伤害回避有关

摘要 强迫症(OCD)患者通常在没有实际威胁的情况下表现出持续的回避行为。强迫症对生活质量的影响和患者之间的异质性使得寻找新的大脑-行为干预目标十分有必要。基于啮齿类动物和非人灵长类动物持续回避行为的机制和解剖学研究&#xff0c;本研究的目标是测试持续回避行为相关…

用于脑肿瘤分割的跨模态深度特征学习| 文献速递-深度学习肿瘤自动分割

Title 题目 Cross-modality deep feature learning for brain tumor segmentation 用于脑肿瘤分割的跨模态深度特征学习 01 文献速递介绍 作为最致命的流行病&#xff0c;脑肿瘤的研究越来越受到关注。本文研究了一种基于深度学习的自动分割胶质瘤的方法&#xff0c;称为脑…

百度ERNIE系列预训练语言模型浅析(4)-总结篇

总结&#xff1a;ERNIE 3.0与ERNIE 2.0比较 &#xff08;1&#xff09;相同点&#xff1a; 采用连续学习 采用了多个语义层级的预训练任务 &#xff08;2&#xff09;不同点&#xff1a; ERNIE 3.0 Transformer-XL Encoder(自回归自编码), ERNIE 2.0 Transformer Encode…

Pandas-中axis的用法

在Pandas中&#xff0c;min(axis)方法是计算DataFrame或Series中每行或每列的最小值的函数。该函数可以接受一个参数axis&#xff0c;用于指定计算最小值的方向。当axis0时&#xff0c;表示沿着行的方向计算最小值&#xff1b;当axis1时&#xff0c;表示沿着列的方向计算最小值…

网络原理-------TCP协议

文章目录 TCP协议TCP协议段格式TCP原理确认应答机制 (安全机制)超时重传机制 (安全机制)连接管理机制 (安全机制)滑动窗口 (效率机制)流量控制 (安全机制)拥塞控制 (安全机制)延迟应答 (效率机制)捎带应答 (效率机制) 基于TCP的应用层协议 TCP协议 TCP, 即 Transmission Contr…