shallowRef和shallowReactive的用法以及使用场景和ref和reactive的区别

devtools/2025/2/3 16:15:11/

Vue3 浅层响应式 API

1. ref vs shallowRef

1.1 基本概念

  • ref: 深层响应式,会递归地将对象的所有属性转换为响应式
  • shallowRef: 浅层响应式,只有 .value 的改变会触发更新,不会递归转换对象的属性

1.2 使用对比

// ref 示例
const deepRef = ref({count: 0,nested: {value: 'hello'}
})// 这些修改都会触发更新
deepRef.value.count++  // 触发更新
deepRef.value.nested.value = 'world'  // 触发更新// shallowRef 示例
const shallowValue = shallowRef({count: 0,nested: {value: 'hello'}
})// 只有直接替换 .value 才会触发更新
shallowValue.value.count++  // 不会触发更新
shallowValue.value.nested.value = 'world'  // 不会触发更新
shallowValue.value = { count: 1 }  // 触发更新

1.3 性能优化示例

<template><div><video ref="videoRef" :src="videoUrl"></video><button @click="updateVideoUrl">更新视频</button></div>
</template><script setup>
import { shallowRef } from 'vue'// 使用 shallowRef 优化大型数据或 DOM 引用
const videoRef = shallowRef(null)
const videoUrl = shallowRef('https://example.com/video.mp4')const updateVideoUrl = () => {// 直接更新 .value 触发更新videoUrl.value = 'https://example.com/new-video.mp4'
}
</script>

2. reactive vs shallowReactive

2.1 基本概念

  • reactive: 深层响应式,递归地将所有嵌套对象转换为响应式
  • shallowReactive: 浅层响应式,只将对象的第一层属性转换为响应式

2.2 使用对比

// reactive 示例
const deepState = reactive({count: 0,nested: {value: 'hello'}
})// 这些修改都会触发更新
deepState.count++  // 触发更新
deepState.nested.value = 'world'  // 触发更新// shallowReactive 示例
const shallowState = shallowReactive({count: 0,nested: {value: 'hello'}
})// 只有第一层属性的改变会触发更新
shallowState.count++  // 触发更新
shallowState.nested.value = 'world'  // 不会触发更新
shallowState.nested = { value: 'world' }  // 触发更新

2.3 实际应用示例

<template><div><h2>用户信息</h2><div>姓名: {{ userInfo.name }}</div><div>年龄: {{ userInfo.age }}</div><!-- 不需要追踪 metadata 的变化 --><div>元数据: {{ userInfo.metadata.lastUpdated }}</div></div>
</template><script setup>
import { shallowReactive } from 'vue'// 使用 shallowReactive 优化性能,metadata 的变化不需要触发更新
const userInfo = shallowReactive({name: 'John',age: 30,metadata: {lastUpdated: new Date(),visits: 0}
})// 只有顶层属性的变化会触发更新
const updateUser = () => {userInfo.name = 'Jane'  // 触发更新userInfo.metadata.visits++  // 不会触发更新
}
</script>

3. 使用场景对比

3.1 适合使用深层响应式(ref/reactive)的场景

  1. 表单数据
const formData = reactive({user: {name: '',email: '',preferences: {newsletter: true,notifications: {email: true,sms: false}}}
})
  1. 需要监听所有层级变化的数据
const settings = ref({theme: {dark: false,colors: {primary: '#000',secondary: '#fff'}}
})

3.2 适合使用浅层响应式(shallowRef/shallowReactive)的场景

  1. 大型数据结构且只需要监听顶层变化
const bigData = shallowRef({items: new Array(10000).fill(0).map((_, i) => ({id: i,data: { /* 大量数据 */ }}))
})// 整体替换数据时才触发更新
const updateData = () => {bigData.value = newBigData
}
  1. 外部库或 DOM 引用
const chartInstance = shallowRef(null)
const mapInstance = shallowRef(null)onMounted(() => {chartInstance.value = new ThirdPartyChart()mapInstance.value = new ThirdPartyMap()
})
  1. 不需要深层响应式的状态管理
const state = shallowReactive({ui: {loading: false,error: null},cache: new Map(), // 不需要响应式的缓存数据helpers: {formatter: () => {}, // 工具函数不需要响应式}
})

4. 性能优化建议

  1. 选择合适的响应式 API
// ✅ 大型数据使用浅层响应式
const bigData = shallowRef(largeDataSet)// ❌ 不必要的深层响应式
const bigData = ref(largeDataSet)
  1. 避免不必要的响应式转换
// ✅ 静态数据使用浅层响应式
const config = shallowReactive({constants: { /* 大量静态配置 */ },settings: { /* 需要响应式的设置 */ }
})// ❌ 对静态数据使用深层响应式
const config = reactive({constants: { /* 大量静态配置 */ },settings: { /* 需要响应式的设置 */ }
})
  1. 合理组合使用
// 混合使用深层和浅层响应式
const state = reactive({// 需要深层响应式的数据userSettings: {theme: 'dark',notifications: { /* ... */ }},// 使用 shallowRef 包装大型数据bigData: shallowRef(largeDataSet)
})

5. 注意事项

  1. 响应式丢失问题
const shallow = shallowReactive({nested: {count: 0}
})// 解构会失去响应性
const { nested } = shallow
nested.count++ // 不会触发更新
  1. 替换整个对象
const data = shallowRef({nested: {value: 0}
})// 需要替换整个对象才能触发更新
data.value = {nested: {value: 1}
}
  1. 与计算属性配合
// 当只需要监听部分数据变化时,使用计算属性
const data = shallowReactive({items: [],metadata: { /* ... */ }
})// 只监听 items 的变化
const computedValue = computed(() => {return processItems(data.items)
})

http://www.ppmy.cn/devtools/155765.html

相关文章

数据结构与算法之栈: LeetCode 641. 设计循环双端队列 (Ts版)

设计循环双端队列 https://leetcode.cn/problems/design-circular-deque/description/ 描述 设计实现双端队列。 实现 MyCircularDeque 类: MyCircularDeque(int k) &#xff1a;构造函数,双端队列最大为 k 。boolean insertFront()&#xff1a;将一个元素添加到双端队列头部…

【开源免费】基于SpringBoot+Vue.JS贸易行业crm系统(JAVA毕业设计)

本文项目编号 T 153 &#xff0c;文末自助获取源码 \color{red}{T153&#xff0c;文末自助获取源码} T153&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

基于微信的课堂助手小程序设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

毕业设计--具有车流量检测功能的智能交通灯设计

摘要&#xff1a; 随着21世纪机动车保有量的持续增加&#xff0c;城市交通拥堵已成为一个日益严重的问题。传统的固定绿灯时长方案导致了大量的时间浪费和交通拥堵。为解决这一问题&#xff0c;本文设计了一款智能交通灯系统&#xff0c;利用车流量检测功能和先进的算法实现了…

ubuntu22.04防火墙策略

Ubuntu 22.04 作为一款流行的Linux发行版&#xff0c;其安全性尤为重要。防火墙是保护系统免受外部威胁的关键组成部分。本文将介绍如何在Ubuntu 22.04上配置和管理防火墙策略&#xff0c;包括使用UFW&#xff08;Uncomplicated Firewall&#xff09;和更为复杂的iptables。 一…

Redis篇 Redis如何清理过期的key以及对应的解决方法

Redis设置Key过期时间 在 Redis 中&#xff0c;可以通过特定的命令为 Key 设置过期时间&#xff0c;使得 Key 在一定时间后自动删除&#xff0c;这对于管理缓存、验证码等临时数据非常有用。 解决方法 1. Redis过期删除策略 1.1 如何实现过期策略 对一个 key 设置了过期时间…

DeepSeek-R1本地部署实践

一、下载安装 --Ollama Ollama是一个开源的 LLM&#xff08;大型语言模型&#xff09;服务工具&#xff0c;用于简化在本地运行大语言模型&#xff0c;降低使用大语言模型的门槛&#xff0c;使得大模型的开发者、研究人员和爱好者能够在本地环境快速实验、管理和部署最新大语言…

Effective Objective-C 2.0 读书笔记—— 方法调配(method swizzling)

Effective Objective-C 2.0 读书笔记—— 方法调配&#xff08;method swizzling&#xff09; 文章目录 Effective Objective-C 2.0 读书笔记—— 方法调配&#xff08;method swizzling&#xff09;前言IMP**SEL 和 IMP 在 objc_msgSend 中的关系** 方法调配实现方法交换 用于…