渐层响应式shallowRef和shallowReactive

渐层响应式shallowRef和shallowReactive

在vue3中,响应式系统可以让我们轻松的追踪到数据的变化。通常我们会使用ref和reactive来定义响应式数据;这两个API都是深度的,ref用来定义基本类型和对象类型的响应式数据,而reactive是用来定义对象类型的响应式数据的;如果因为性能原因我们并不想追踪很深的响应式的,这个时候我们就需要使用shallowRef和shallowReactive来对数据进行渐层的处理

1. 回顾ref和reactive

vue 复制代码
<template>
  <h2>ref姓名:{{ deepRef.user.name }}</h2>
  <h2>ref年龄:{{ deepRef.user.age }}</h2>
  <h2>reactive姓名:{{ deepReactive.user.name }}</h2>
  <h2>reactive姓名:{{ deepReactive.user.age }}</h2>
  <button @click="ChangeName">修改姓名</button>
  <button @click="ChangeAge">修改年龄</button>
</template>
<script setup>
import { ref, reactive } from 'vue'
const deepRef = ref({ user: { name: 'Alice', age: 20 } })
const deepReactive = reactive({ user: { name: 'Bob', age: 25 } })
function ChangeName() {
  deepRef.value.user.name = '张三'
}

function ChangeAge() {
  deepReactive.user.age += 1
}

</script>

这样修改数据没有一点问题

2.shallowRef

  • 如果更改成shallowRef则不会起作用
vue 复制代码
const deepRef = shallowRef({ user: { name: 'Alice', age: 20 } })

这样点击并不会其任何作用,因为shallowRef只跟踪到deepRef.value,至于deepRef.value.user并不会被它追踪到,那么shallowRef到底有什么作用呢?

什么时候使用shallowRef?

当你有一个大型的、嵌套非常深的对象且你只需关心这个对象整体有没有被替换,不关心内部到底那里更换了,使用它可以消除很深的性能开销;常于markRaw配合使用,跳过某些大对象的响应式转换,例如

  • 比如我们有一个配置文件,这个配置文件类似json一样有一大堆数据,我们并不需要修改数据中某一项,只要修改就是整体替换,避免修改某一项导致配置文件失效出错
vue 复制代码
<template>
  <div>
    <pre>{{ config }}</pre>
    <button @click="updateConfig">更新配置</button>
  </div>
</template>
<script setup>
import { shallowRef } from 'vue';
const config = shallowRef({
  theme: 'dark',
  layout: {
    header: true,
    footer: false
  }
})

function updateConfig() {
  // 整体替换,触发更新
  config.value = {
    ...config.value,
    theme: 'light',
    layout: { header: false, footer: true }
  }
}

</script>
<style></style>

3.shallowReactive

这个也是类似shallowRef,当时响应式对象里面还有一个对象,里面的对象就并不能深度追踪到了

vue 复制代码
<template>
  <div>
    <p>计数:{{ state.count }}</p>
    <p>用户:{{ state.user.name }}</p>
    <button @click="increment">增加 count</button>
    <button @click="changeUserName">修改用户名</button>
  </div>
</template>
<script setup>
import { shallowReactive } from 'vue';
const state = shallowReactive({
  count: 0,
  user: { name: 'Alice' }   // user 不是响应式的
})
function increment() {
  state.count++   // 会触发更新
}

function changeUserName() {
  state.user.name = 'Bob'   // 不会触发更新,界面上的用户名不会改变
  // 但如果想要更新,可以整体替换 user 对象:
  // state.user = { name: 'Bob' }   // 这会触发更新,因为替换了顶层属性
}
</script>

什么时候使用shallowReactive?

比如你有一个对象,只希望顶层是响应式的,而内部嵌套不需要被追踪时;例如一个表单对象,里面包含了和上面一样含有复杂的配置对象,这个配置永远都不需要变动,或者它只是只读的;、

实际使用中我们可以使用markRaw来标记某个对象永远都不会是响应式的

vue 复制代码
import { shallowRef, markRaw } from 'vue'

const hugeObject = markRaw({ /* 巨大的静态数据 */ })
const state = shallowRef(hugeObject)

// 现在 state.value 中的任何属性变化都不会触发响应式更新
// 只有整体替换 state.value 时才会更新
相关推荐
随风一样自由8 小时前
【前端独角兽】刚进入前端领域的前端开发用jQuery还是Vue3?
前端·javascript·vue3·jquery
IMPYLH8 小时前
HTML 的 <data> 元素
前端·html
YHHLAI9 小时前
[特殊字符] 面试中的 Promise —— 从入门到精通
前端·javascript·面试
weixin_BYSJ19879 小时前
SpringBoot + MySQL 乒乓球运动员信息管理系统项目实战--附源码04954
java·javascript·spring boot·python·django·flask·php
沪飘大军10 小时前
ll-llm:一个零依赖、可插拔的 OpenAI 兼容 LLM 代理
javascript
leoZ23110 小时前
Claude 驱动的全栈开发:Spring Boot + Vue 的 BS 架构实践
vue.js·spring boot·架构
kyriewen11 小时前
我扒了 GPT-5.6 的全部编程跑分——有一项 OpenAI 没敢放出来
前端·gpt·ai编程
前端H11 小时前
微前端 v3 架构升级:从加载隔离到状态协同
前端·架构·状态模式
山河木马11 小时前
GPU自动处理专题3-NDC怎么映射成屏幕像素坐标(视口变换)
javascript·webgl·图形学
陆枫Larry12 小时前
小程序包体积优化:用 SVG 图片替换 iconfont,并保留 CSS 控色能力
前端