渐层响应式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 时才会更新
相关推荐
@yanyu6662 小时前
05计算属性与定时器
前端·javascript·vue.js
哈__2 小时前
ReactNative项目OpenHarmony三方库集成实战:react-native-chart-kit
javascript·react native·react.js
小同志002 小时前
JQuery
前端·javascript·jquery
秋田君2 小时前
【Vue实战】打造全能文件预览组件:支持PDF/Word/Excel/PPT/图片/音视频及Markdown(基于vue-office)
vue.js·文档预览·vue-office
就是个名称2 小时前
Chrome使用cesium.js或者three.js报错不支持webGL
javascript·chrome·webgl
zdl6862 小时前
SpringBoot返回文件让前端下载的几种方式
前端·spring boot·后端
拾贰_C2 小时前
【Vue | vue3 | spring boot】前端前台项目搭建
前端·vue.js·spring boot
Irene19912 小时前
flush 是 Vue3 中控制副作用函数执行时机的配置选项,用于决定响应式数据变化后,副作用(watch、watchEffect、组件渲染)在何时执行
vue.js
用户90443816324602 小时前
大三面字节被问懵?手撕 WebSocket 与 SSE 底层原理,大厂通关指南
前端·面试