当前位置: 首页 > news >正文

解密 Vue 3 shallowRef:浅层响应式 vs 深度响应式的性能对决

📖 概述

shallowRef() 是 Vue 3 中的一个组合式 API 函数,用于创建浅层响应式引用。与 ref() 不同,shallowRef() 只在其 .value 被直接替换时触发响应式更新,不会深度监听对象内部属性的变化。

🎯 基本概念

什么是 shallowRef?

shallowRef() 创建一个响应式引用,但只在其值被完全替换时触发更新,不会深度监听对象或数组内部的变化。这提供了更好的性能,特别适用于大型对象或不需要深度响应式的场景。

使用场景

  • 🚀 性能优化:处理大型对象或数组
  • 🎮 游戏开发:频繁更新的状态管理
  • 📊 数据可视化:大量数据的响应式处理
  • 🔧 第三方库集成:避免深度响应式监听

🔧 函数签名

function shallowRef<T>(value: T): ShallowRef<T>;interface ShallowRef<T> {value: T;
}

💻 代码示例

🚀 基础用法

<script setup lang="ts">
import { shallowRef, ref } from "vue";// 创建浅层响应式引用
const shallowData = shallowRef({ count: 0, name: "Vue" });
const deepData = ref({ count: 0, name: "Vue" });// 直接替换值会触发更新
shallowData.value = { count: 1, name: "Vue3" };// 修改内部属性不会触发更新
shallowData.value.count = 2; // ❌ 不会触发响应式更新// 而 ref 会深度监听
deepData.value.count = 2; // ✅ 会触发响应式更新
</script>

📊 大数据处理

<script setup lang="ts">
import { shallowRef, onMounted } from "vue";// 大型数据集
const largeDataset = shallowRef([]);onMounted(async () => {// 模拟获取大量数据const data = await fetchLargeDataset();largeDataset.value = data; // ✅ 一次性更新,性能更好
});// 批量更新数据
const updateDataset = (newData: any[]) => {largeDataset.value = newData; // ✅ 触发更新
};
</script>

⚖️ 与 ref 的对比

🔍 深度响应式(ref)

<script setup lang="ts">
import { ref } from "vue";const user = ref({ name: "Alice", age: 25 });// 修改内部属性会触发更新
user.value.age = 26; // ✅ 触发响应式更新
user.value.name = "Bob"; // ✅ 触发响应式更新
</script>

🎯 浅层响应式(shallowRef)

<script setup lang="ts">
import { shallowRef } from "vue";const user = shallowRef({ name: "Alice", age: 25 });// 修改内部属性不会触发更新
user.value.age = 26; // ❌ 不会触发响应式更新
user.value.name = "Bob"; // ❌ 不会触发响应式更新// 只有完全替换对象才会触发更新
user.value = { name: "Bob", age: 26 }; // ✅ 触发响应式更新
</script>

⚠️ 注意事项

🔄 触发更新的方式

shallowRef 只在以下情况触发响应式更新:

<script setup lang="ts">
import { shallowRef } from "vue";const data = shallowRef({ count: 0 });// ✅ 会触发更新
data.value = { count: 1 };// ❌ 不会触发更新
data.value.count = 1;
data.value.nested = { value: 1 };
</script>

🎯 与 reactive 的区别

shallowRef 和 shallowReactive 的区别:

<script setup lang="ts">
import { shallowRef, shallowReactive } from "vue";// shallowRef - 需要 .value 访问
const refData = shallowRef({ count: 0 });
console.log(refData.value.count);// shallowReactive - 直接访问
const reactiveData = shallowReactive({ count: 0 });
console.log(reactiveData.count);
</script>

🔧 手动触发更新

如果需要手动触发更新,可以使用 triggerRef

<script setup lang="ts">
import { shallowRef, triggerRef } from "vue";const data = shallowRef({ count: 0 });// 修改内部属性
data.value.count = 1;// 手动触发更新
triggerRef(data); // ✅ 强制触发响应式更新
</script>

🎯 最佳实践

1️⃣ 性能优化场景

在需要处理大型对象或频繁更新的场景中使用:

<script setup lang="ts">
import { shallowRef, computed } from "vue";// 大型配置对象
const config = shallowRef({theme: "dark",language: "zh-CN",settings: {/* 大量配置项 */},
});// 只在配置完全替换时更新
const updateConfig = (newConfig: typeof config.value) => {config.value = newConfig;
};
</script>

2️⃣ 避免不必要的深度监听

当不需要监听对象内部变化时使用:

<script setup lang="ts">
import { shallowRef } from "vue";// 只关心整体替换,不关心内部变化
const userProfile = shallowRef({id: 1,name: "Alice",preferences: { theme: "dark", notifications: true },
});// 更新整个用户资料
const updateProfile = (profile: typeof userProfile.value) => {userProfile.value = profile;
};
</script>

3️⃣ 结合 triggerRef 使用

在需要精确控制更新时机时:

<script setup lang="ts">
import { shallowRef, triggerRef } from "vue";const formData = shallowRef({name: "",email: "",message: "",
});// 批量更新后手动触发
const updateForm = (updates: Partial<typeof formData.value>) => {Object.assign(formData.value, updates);triggerRef(formData); // 手动触发更新
};
</script>

❓ 常见问题

Q: 什么时候使用 shallowRef 而不是 ref?

A: 当处理大型对象、频繁更新的数据,或不需要深度响应式监听时使用 shallowRef。

Q: shallowRef 会影响计算属性吗?

A: 计算属性会正常响应 shallowRef 的变化,但不会响应其内部属性的变化。

Q: 如何强制 shallowRef 更新?

A: 使用 triggerRef() 函数可以强制触发 shallowRef 的响应式更新。

📝 总结

shallowRef() 是 Vue 3 中用于性能优化的强大工具,特别适用于处理大型对象、频繁更新的状态,以及不需要深度响应式监听的场景。通过合理使用 shallowRef(),可以显著提升应用性能,同时保持必要的响应式能力。记住,只有在完全替换值时才会触发更新,如需手动控制更新时机,可以使用 triggerRef()

 解密 Vue 3 shallowRef:浅层响应式 vs 深度响应式的性能对决 - 高质量源码分享平台-免费下载各类网站源码与模板及前沿技术分享

http://www.dtcms.com/a/356360.html

相关文章:

  • 园区智慧水电管理系统:让能源管理从“成本黑洞”变“利润引擎”
  • 【GM3568JHF】FPGA+ARM异构开发板 使用指南:以太网
  • nginx 怎么将 https 请求转为 http
  • AR巡检系统:数字化传统工作流程SOP的第一步
  • //Q是一个队列,S是一个空栈,实现将队列中的元素逆置的算法。
  • 从零开始学习单片机17
  • 医疗AI时代的生物医学Go编程:高性能计算与精准医疗的案例分析(五)
  • AR智能眼镜:能源行业运维的数字化革新
  • iOS 文件管理与 uni-app 性能优化实战 多工具协作的完整指南
  • Frida-dexdump 使用指南:从内存中脱取安卓 Dex 文件
  • Go对接全球期货数据源指南:基于StockTV API实现多品种实时监控
  • LeetCode第二题知识点2 ---- 栈、堆、地址
  • 不止 ChatGPT:多模态 AI(文本 + 图像 + 音频)正重构内容创作全流程
  • 数据质检之springboot通过yarn调用spark作业实现数据质量检测
  • 第三章 Vue3 + Three.js 实战:用 OrbitControls 实现相机交互与 3D 立方体展示
  • Unity学习----【数据持久化】二进制存储(一)
  • ExcelJS实现导入转换HTML展示(附源码可直接使用)
  • Excel数组学习笔记
  • 在Excel和WPS表格中隔一行插入多个空白行
  • 网络编程 04:TCP连接,客户端与服务器的区别,实现 TCP 聊天及文件上传,Tomcat 的简单使用
  • 从零开始部署 Kubernetes Dashboard:可视化管理你的集群
  • [Linux]学习笔记系列 -- mm/shrinker.c 内核缓存收缩器(Kernel Cache Shrinker) 响应内存压力的回调机制
  • 创意程序之MP3分割工具
  • sqlachemy
  • AI操作系统语言模型设计 之1 基于意识的Face-Gate-Window的共轭路径的思维-认知-情感嵌套模型
  • 【C语言】深入理解指针(2)
  • 龙迅#LT7621GX适用于两路HDMI2.1/DP1.4A转HDMI2.1混切应用,分辨率高达8K60HZ!
  • 第二阶段WinForm-11:自定义控件
  • 嵌入式Linux驱动开发:i.MX6ULL中断处理
  • 深入解析Qt节点编辑器框架:交互逻辑与样式系统(二)