渐层响应式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 时才会更新
相关推荐
爱勇宝1 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
kyriewen1 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
user20585561518134 小时前
Windows 项目安装时报 `node-sass` 错误,如何快速处理
前端
LiaCode4 小时前
Redis 在生产项目的使用
前端·后端
LiaCode4 小时前
一天学完 redis 的爽翻版核心知识总结
前端·后端
大刚测试开发实战4 小时前
如何内网穿透访问本地私有化部署的TestHub
前端·后端·github
风骏时光牛马4 小时前
# Ruby基于Rails框架实现多角色权限管理与数据分页查询完整实战代码案例
前端
weedsfly4 小时前
迭代器、生成器与异步迭代——让数据“按需流动”的艺术
前端·javascript
xiaodaoluanzha4 小时前
迄今為止,最簡單的編程語言 Nolang
前端·后端
Csvn4 小时前
Fetch 请求竞态终结者:AbortController 不只是用来"取消"的
前端