vue3响应式用法(高阶性能优化)

文章目录

    • 前言:
    • 一、 shallowRef()
    • 二、 triggerRef()
    • 三、 customRef()
    • 四、 shallowReactive()
    • 五、 toRaw()
    • 六、 markRaw()
    • 七、 shallowReadonly()
    • 小结:

在这里插入图片描述

前言:

翻别人代码时,总结发现极大部分使用vue3的人只会用refreactive处理响应式数据无论什么场景都是,但vue官方针对某些应用场景有其它的更好用的响应式api实现响应式,从而达到更好的性能效果。例如深层的树状数据结构可以通过shallowRef实现浅层响应式,不会被深层递归地转为响应式。本文通过例子详细总结几种vue3响应式的高阶用法。

一、 shallowRef()

简述:ref的浅层作用形式。shallowRef与普通的 ref 的区别在于,shallowRef 不会对对象进行深度的响应式处理,也就是 shallowRef 包含的对象内部的属性发生变化时,shallowRef 本身不会触发重新渲染或响应式更新,所以使用shallowRef时只关心顶层的引用变化。

代码示例:

<script lang="ts" setup>import { shallowRef } from 'vue';const data = shallowRef({ name: '天天鸭', age: 18 });// 修改顶层引用会触发响应式更新data.value = { name: 'Bob', age: 20 };// 修改内部属性不会触发响应式更新data.value.age = 30;
</script>

作为性能优化的一种手段,当业务场景中有大量复杂数据结构但只有顶层引用需要响应式时就非常有用,但你需要更加注意对象的更新逻辑,确保在需要时正确地应用响应式转换。

二、 triggerRef()

简述:用于强制执行依赖于 shallowRef 的副作用。也就是说当使用shallowRef响应式时只能修改顶层数据,但特殊情况使用 triggerRef可以强制修改内层属性,大大提高灵活性。

代码示例:

<script lang="ts" setup>import { shallowRef, triggerRef } from 'vue';const data = shallowRef({ name: '天天鸭', age: 18 });// 修改内部属性不会触发响应式更新data.value.age = 30;// 但这里调用 triggerRef 强制更新triggerRef(data);
</script>

triggerRef 一般配合shallowRef一起使用,起到提高shallowRef的灵活性的同时又能优化性能的效果。需要注意执行顺序确保在修改了 shallowRef 内部对象的属性之后才调用。

三、 customRef()

简述:customRef 功能非常之强大,customRef可以创建自定义的 ref 对象,这些对象可以有更复杂的依赖跟踪和依赖更新逻辑。具体是customRef 接收一个工厂函数,该函数必须要返回一个具有 getset 方法的对象。这些方法用于读取和修改引用值,并且通过getset里面的逻辑可以显式地控制依赖关系的跟踪和响应式更新。

代码示例: 实现一个有防抖功能的ref,第9和17行的track()trigger()是固定写法,这是vue3底层响应式原理相关的,这里就不多解释了。

<script lang="ts" setup>
import { customRef } from 'vue';function debouncedRef(initialValue, delay) {let timeoutId;return customRef((track, trigger) => ({get() {// 使用 track 函数标记依赖track();return initialValue;},set(newValue) {clearTimeout(timeoutId);timeoutId = setTimeout(() => {initialValue = newValue;// 使用 trigger 函数触发依赖更新trigger();}, delay);}}));
}// 使用自定义的ref
const myDebouncedRef = debouncedRef('Hello Word', 500);
</script>

在上述例子中,debouncedRef 是一个自定义的 ref 工厂函数,它接收两个参数分别是初始值和延迟时间。当 set 方法被调用时,会清除之前的计时器并设置一个新的计时器,在延迟时间结束后更新值并触发依赖更新。

在组件中使用:

<script lang="ts" setup>
import { onMounted } from 'vue';
import { debouncedRef } from './debouncedRef';export default {setup() {const myDebouncedRef = debouncedRef('Hello Word', 500);onMounted(() => {// 在组件挂载后,可以通过 .value 访问 ref 的值console.log(myDebouncedRef.value);  // 时间到之后返回 'Hello Word'});},
};
</script>

注意: customRef 返回的对象必须有一个 value 属性用于访问或修改引用的值,这是 vue 规定的。除此以外customRef能根据业务需求实现各种定制化的ref, 如异步更新、条件性更新、防抖、节流等

四、 shallowReactive()

简述:reactive的浅层作用形式, 和shallowRef的功能比较类似。shallowReactive与普通的 reactive 的区别在于,shallowReactive 不会对对象进行深度的响应式处理,也就是 shallowReactive 包含的对象内部的属性发生变化时,shallowReactive 本身不会触发重新渲染或响应式更新,所以使用shallowReactive时只关心顶层的引用变化。

代码示例:

<script lang="ts" setup>import { shallowReactive, isReactive } from 'vue';const statetest = shallowReactive({foo: 1,nested: {age: 18,},});statetest.foo++;    // 更改状态自身的属性是响应式的// 下层嵌套对象不会被转为响应式isReactive(statetest.nested); // falsestatetest.nested.age++;     // 不是响应式的
</script>

作为性能优化的一种手段,当业务场景中有大量复杂数据结构但只有顶层引用需要响应式时就非常有用,但你需要更加注意对象的更新逻辑,确保在需要时正确地应用响应式转换。

五、 toRaw()

简述:toRaw用于获取 reactiveref 创建的响应式代理对象的原始值。当我们使用 reactiveref 创建一个对象或值时,Vue 会在内部创建一个代理对象,这个代理对象能够追踪属性的变化并触发视图的更新。但有时候需要访问这个对象的非响应式版本时toRaw 就派上用场了。

代码示例:

<script lang="ts" setup>import { reactive, toRaw } from 'vue';const state = reactive({ count: 0 });// 获取响应式转为原始对象const rawState = toRaw(state);// 修改原始对象不会触发响应式更新rawState.count = 10;// 仍然输出 0,因为 state 是响应式代理,未被修改console.log(state.count); 
</script>

使用 toRaw 获取的原始对象将不再具有响应性。即toRaw 提供了一种方式来绕过 Vue 的响应式系统,这对于性能优化和处理外部库至关重要。当正在处理一个大的数据结构,并且知道某些操作不会导致 UI 更新时使用特别合适。

六、 markRaw()

简述:作用是标记一个对象,使其不再被 reactiveshallowReactive 转换为响应式代理。即你之后试图用这些函数包装这个对象,它也会保持原样,不会变成响应式的。

代码示例: markRaw 主要用于标记对象,而不是基本类型的值

<script lang="ts" setup>import { markRaw } from 'vue';const someObject = { name: '天天鸭' };const markedObject = markRaw(someObject);// 即使使用 reactive,markedObject 也不会变成响应式const state = reactive({ obj: markedObject });
</script>

注意: markRaw不适用于ref,因为ref 的工作方式与 reactive 有点区别。ref 主要用于创建一个响应式引用,它可以封装任何类型的值如字符串、数字和对象。当你创建一个 ref 时,Vue 并不是将整个对象转换为响应式代理,而是将 ref 本身作为一个响应式引用,通过 value 属性来访问和修改其内部的值。

因此,当你将一个对象放入 ref 时,ref 本身依然是响应式的,而 markRaw 的作用是阻止对象被转换为响应式,这和 ref 的设计并不匹配。

七、 shallowReadonly()

简述:readonly 的浅层作用形式。和 readonly 类似,shallowReadonly 会把对象的属性变为只读,但是它只会影响到对象的顶层属性,而不会递归地使对象内部的属性也变为只读。

代码示例:

<script lang="ts" setup>
import { shallowReadonly } from 'vue';const state = {name: '天天鸭',profile: {age: 18,address: {city: '广州',}}
};
const shallowState = shallowReadonly(state);// 这将会抛出错误,因为顶层属性是只读的
shallowState.name = 'change天天鸭';// 这是可以的,因为 `profile` 对象没有被设为只读
shallowState.profile.age = 31; // 同样,`address` 对象也可以被修改
shallowState.profile.address.city = '深圳';
</script>

使用 shallowReadonly 的对象在顶层是只读的,但其内部的嵌套对象或数组仍然可以被修改。如果数据结构第一层业务需求不会改变就特别适用。

小结:

在真实做项目时其实不用这些进阶用法同样能实现功能,但是在合适的场景用上了却能锦上添花,作为一个有一定经验的vue程序员更是要必会了。如果我写的哪里不对或者不好欢迎大佬指出。

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

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

相关文章

mysql-bin 恢复数据库

能看到这里的同学估计肯定摊上大事了吧&#xff01;不要慌&#xff0c;一定要冷静&#xff0c;记录一下作者的大事件吧&#xff0c;黑客通过SQL注入的方式执行了一段SQL &#xff1a; DROP DATABASE ****** 后果就是导致整个数据库被删了&#xff0c;当时心是拔凉拔凉的&#x…

在jmeter中使用javascript脚本

工作上遇到一个压力测试的需求&#xff0c;需要测试几个考试相关的接口。其中有一个获取试题详情的接口&#xff0c;和一个提交答题信息的接口。后一个接口以上一接口的返回内容为参数&#xff0c;添加上用户的答案即可。jmeter提供了非常多的方式可以实现该需求&#xff0c;这…

【深度学习】大模型GLM-4-9B Chat ,微调与部署(3) TensorRT-LLM、TensorRT量化加速、Triton部署

文章目录 获取TensorRT-LLM代码&#xff1a;构建docker镜像并安装TensorRT-LLM&#xff1a;运行docker镜像&#xff1a;安装依赖魔改下部分package代码&#xff1a;量化&#xff1a;构建图&#xff1a;全局参数插件配置常用配置参数 测试推理是否可以代码推理CLI推理 性能测试小…

钡铼网关实时数据互联,加速IEC104与MQTT云平台对接

随着工业4.0时代的到来&#xff0c;电力系统中的数据采集、监控与远程控制需求日益增长。IEC 104&#xff08;IEC 60870-5-104&#xff09;作为国际电工委员会&#xff08;IEC&#xff09;制定的电力自动化通信协议&#xff0c;广泛应用于电力系统的状态监测、数据采集和设备控…

Vue实现简单小案例

一、创建文件夹 二、引用vue.js <script src"../js/vue.js"></script> 三、准备一个容器 <div id"app"><h1>Hello,{{name}}</h1> </div> 四、创建实例 <script>new Vue({el:"#app", //el用于指…

【STM32 FreeRTOS】FreeRTOS的移植

其实这篇文章不侧重移植&#xff0c;因为我们会使用CubeMX配置&#xff0c;那样会自动移植FreeRTOS。 关于FreeRTOS&#xff0c;可以参考官网&#xff1a;FreeRTOS - Quick start guide 当我们在CubeMX中配置了CMSIS_V2后尝试编译的时候会有一个弹窗。 第一个问题就是强烈建议…

【深度学习】yolov8-det目标检测训练,拼接图的分割复原

项目背景 https://blog.csdn.net/x1131230123/article/details/140606459 似乎这个任务是简单的&#xff0c;利用目标检测是否可以完成得好呢? 生成数据集 利用这个代码产生数据集&#xff1a; 为了将标签转换为YOLOv5格式&#xff0c;需要将左上角和右下角的坐标转换为Y…

【性能测试-登录时密码加密存储如何传参】

目的】 登录接口&#xff0c;密码加密传输&#xff0c;开发不做处理的情况下&#xff0c;密码如何加密传输 【方案】 使用前置处理器&#xff1a;JSR223 预处理程序&#xff0c;主要是在执行登录接口前将密码按照加密算法获得对应的加密密码&#xff0c;并传入接口 【说明】前…

如何对视频文件加密_如何加密视频文件_视频文件如何加密

“嘿&#xff0c;小李&#xff0c;你知道咱们公司的新项目资料都是视频形式的吗&#xff1f;这些视频里有很多机密信息&#xff0c;我们需要好好保护起来。” “是啊&#xff0c;我也在想这个问题。你有没有什么好办法来加密这些视频文件呢&#xff1f;” “我听说有个叫域智盾…

生成式AI的双重路径:Chat与Agent的融合与竞争

文章目录 每日一句正能量前言整体介绍对话系统&#xff08;Chat&#xff09;自主代理&#xff08;Agent&#xff09;结论 技术对比技术差异优势与劣势技术挑战结论 未来展望发展趋势Chat与Agent的前景社会和经济影响结论 后记 每日一句正能量 在避风的港湾里&#xff0c;找不到…

代码随想录算法训练营第38天|LeetCode 322. 零钱兑换、279.完全平方数、139.单词拆分

1. LeetCode 322. 零钱兑换 题目链接&#xff1a;https://leetcode.cn/problems/coin-change/description/ 文章链接&#xff1a;https://programmercarl.com/0322.零钱兑换.html 视频链接&#xff1a;https://www.bilibili.com/video/BV14K411R7yv/ 思路&#xff1a; 硬币无限…

实现领域驱动设计(DDD)系列详解:领域模型的持久化

领域驱动设计主要通过限界上下文应对复杂度&#xff0c;它是绑定业务架构、应用架构和数据架构的关键架构单元。设计由领域而非数据驱动&#xff0c;且为了保证定义了领域模型的应用架构和定义了数据模型的数据架构的变化方向相同&#xff0c;就应该在领域建模阶段率先定义领域…

我的世界!

每位冒险家在《我的世界》中的出生点都各不相同&#xff0c; 有的出生在桦木森林&#xff0c;有的出生在草原&#xff0c; 还有的出生在临近海洋的沙滩。 这些环境叫做生物群系&#xff0c;也常被称为生态系统。 在《我的世界》中的不同生物群系具有不同的地域特色—— 不…

本地化部署一个简单的AI大模型,Llama3.1

7 月 23 日消息&#xff0c;Meta 今晚正式发布llama3.1&#xff0c;提供 8B、70B 及 405B 参数版本。 Meta 称 4050 亿参数的 Llama 3.1-405B 在常识、可引导性、数学、工具使用和多语言翻译等一系列任务中&#xff0c;可与 GPT-4、GPT-4o、Claude 3.5 Sonnet 等领先的闭源模型…

Qt遇到qt自身组件找不到

比如在使用qtcharts的时候&#xff0c;找不到 解决方法&#xff1a; 在cmakelist中添加 find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Charts REQUIRED) 是一个 CMake 命令&#xff0c;用于查找并配置 Qt 库中的特定组件。这条命令的作用是找到 Qt 的主要版本&#xff08;…

ST Stellar-E SR5E1 22KW OBC combo 3KW DC-DC汽车充电器解决方案

对于全球的环境保护意识抬头&#xff0c;全球的汽车产业慢慢步入电动化的时代&#xff0c;以减少碳排放。整车系统主要是由电池、电驱、电控的三电所构成&#xff0c;其中电池系统是整车的动力来源&#xff0c;而对电池充电的OBC系统更甚重要。一具高度安全性且高效的OBC系统&a…

MybatisPlus设置动态表名

对于一些数据量比较大的表&#xff0c;为了提高查询性能&#xff0c;我们一般将表拆分成多张表&#xff0c;常见的是根据数据量&#xff0c;按年分表或者按月分表&#xff1b;分表虽然太高了查询性能&#xff0c;但是在查询的时候&#xff0c;如何才能查询执行分表数据呢&#…

7.25扣...

思路&#xff1a;别的语言都可以不用辅助数组&#xff0c;我Java就得用&#xff01; c:先计算字符串中数字个数&#xff0c;然后利用双指针将原本字符串逆序从数组最后往前插入&#xff0c;若遇到数字则替换为逆序的“number”&#xff0c;这个过程会使新字符串从后往前覆盖&am…

UI界面卡顿检测工具--UIHaltDetector

引言&#xff1a; 在日常工作当中&#xff0c;我们经常会遇到软件的界面出现卡顿的问题&#xff0c;而为了确定卡顿原因&#xff0c;我特地写了一个UI界面卡顿的小工具&#xff1a;UIHaltDetector&#xff1b;该工具可以在检测到目标窗口出现卡顿的时候直接打印堆栈日志和输出…

MySQL SQL 编程练习

目录 创建表并插入数据 查看表结构 创建触发器 创建INSERT 触发器 创建DELETE 触发器 创建更新触发器 创建存储过程 创建提取emp_new表所有员工姓名和工资的存储过程s1 创建存储过程s2&#xff0c;实现输入员工姓名后返回员工的年龄 创建一个存储过程s3&#xff0c;有2个参数&…