Vue3浅层响应式API全解析:shallowRef、shallowReactive与shallowReadonly深度探索‌

Vue 3 浅层响应式 API 全解析:shallowRef、shallowReactive 与 shallowReadonly 深度探索


目录

  1. 前言
  2. 为什么需要“浅层”响应式
  3. 浅层 API 一览

    • 3.1 shallowRef
    • 3.2 shallowReactive
    • 3.3 shallowReadonly
  4. 与常规 ref/reactive/readonly 的对比

    • 4.1 深度 vs 浅层:响应式行为对比
    • 4.2 性能与使用场景
  5. shallowRef 详解

    • 5.1 基本概念与语法
    • 5.2 代码示例
    • 5.3 内部原理剖析(图解)
    • 5.4 使用场景与注意事项
  6. shallowReactive 详解

    • 6.1 基本概念与语法
    • 6.2 代码示例
    • 6.3 内部原理剖析(图解)
    • 6.4 使用场景与注意事项
  7. shallowReadonly 详解

    • 7.1 基本概念与语法
    • 7.2 代码示例
    • 7.3 内部原理剖析(图解)
    • 7.4 使用场景与注意事项
  8. 综合示例:三种浅层 API 联合使用
  9. 常见误区与解答
  10. 总结

前言

Vue 3 推出了全新的响应式系统(基于 Proxy 实现),不仅在性能上大幅提升,还提供了更多灵活的 API 供开发者使用。其中,浅层响应式(shallow)API 是一个“轻量级”选项,让我们在只需要对顶层属性进行响应式跟踪时,大幅减少不必要的代理开销。本文将从概念、原理、代码示例和实战角度,深度解析 shallowRefshallowReactiveshallowReadonly 三个 API,让你对“浅层响应式”有更直观清晰的认识。

本文适合已经了解 Vue 3 普通 ref/ reactive/ readonly 基础用法的开发者。如果你对 Vue 3 响应式系统有初步了解,但不清楚“何时需要浅层响应式”、“浅层响应式如何实现”、以及“浅层与深度响应式的具体差异”,请耐心阅读,相信本文能够帮你快速上手并灵活运用这三种 API。


为什么需要“浅层”响应式

在实际项目中,我们常常面临下面几种场景:

  1. 大而深的对象
    某个状态可能是一个深度嵌套的对象(例如:复杂配置、第三方数据),但我们只关注顶层某个引用是否变化,而不需要追踪内部每一个属性的实时更新。
  2. 外部数据接管
    当你从接口获取了一个大型对象,并不想对其内部逐层代理,只需要知道何时整块数据引用改变。
  3. 性能瓶颈
    深度递归地为每个属性和子属性都创建 Proxy,虽然 Vue 3 的 Proxy 性能已经很出色,但对于特别巨量的对象,还是会有额外的内存与运行时消耗。

如果使用普通的 refreactive,Vue 会对整个对象进行深度代理,对每层属性进行依赖收集与触发,开销相对较大。而“浅层”响应式则只对最外层进行代理,内部层级在第一次访问时并不会再被转换成响应式。这样,在“只关心外层引用”或“只需浅层响应式”的场景里,就能大幅节省框架开销。


浅层 API 一览

Vue 3 共提供了三种浅层版本的响应式 API:

  • shallowRef(value)
    与普通 ref 相比,只会对 value 本身建立响应式,而不会递归地将 value 内部的对象/数组转换为响应式。
  • shallowReactive(object)
    与普通 reactive 相比,只会对 object 顶层属性建立 Proxy,而不对嵌套对象进行深度转换。
  • shallowReadonly(object)
    与普通 readonly 相比,只会对 object 顶层属性建立只读(无法修改),但内部嵌套对象仍是“可写”的普通对象。

下面,我们会分别对这三个 API 进行深入剖析,并通过示例与图解来帮助你理解它们之间的异同。


与常规 ref/reactive/readonly 的对比

在讲各个浅层 API 之前,我们先从整体上对比一下“深度”与“浅层”响应式的区别。

深度 vs 浅层:响应式行为对比

API响应式深度顶层访问响应式嵌套属性访问响应式修改内部属性是否触发外层依赖更新
ref(value)仅值层(如果 value 是基本类型)
如果 value 是对象,则深度代理(递归)
reactive(object)深度递归代理
shallowRef(value)仅顶层(不递归)❌(内部不代理)❌(内部改动不会触发)
shallowReactive(obj)顶层属性(不递归)
readonly(object)深度递归只读—— (无法修改,抛错或警告)
shallowReadonly(obj)顶层属性只读❌(内部可写)可写但不会触发只读警告
  • 深度递归reactivereadonly 会在访问任何一层嵌套属性时,都自动将其转换为 Proxy,并对其进行依赖收集或只读保护。
  • 浅层 版本则只对最外层进行响应式或只读,内部嵌套对象保持原始状态。当你访问二级或多级属性时,Vue 不会再转换成 Proxy,也不会收集依赖。

性能与使用场景

场景使用“深度”API使用“浅层”API
需要对子属性进行精细化追踪与渲染×
只需要顶层引用或属性更改即可触发视图更新√(可用)√(推荐,减少代理开销)
数据对象非常庞大且深度嵌套,不关注内部字段变化×(性能低)√(浅层代理,更轻量)
需要浅层只读保护,内部子属性仍可写×(会报错或警告)√(只对顶层只读,内部可写)
外部传入的外部库对象,仅需监听何时整体替换×(会代理内部)√(只代理最外层引用)

关键要点:

  • 若你只关心 外层引用/属性 的变化,或不想对子对象嵌套层级都进行代理,那么使用 浅层 API 更合理,也能带来性能优势。
  • 若你需要对内部字段进行深度追踪与响应,则应使用深度 API(普通 reactive / readonly / ref)。

shallowRef 详解

5.1 基本概念与语法

import { shallowRef } from 'vue';
  • shallowRef(value) 会返回一个对象 { value: value },与普通 ref 类似。
  • 差异在于: 如果 value 是一个对象/数组,调用 shallowRef 时 Vue 只会在最外层对其做一个响应式容器(拦截对 ref.value 本身的赋值/读取),而不会递归地将 value 内部的属性转为响应式。

典型用法:

const obj = { a: 1, b: { c: 2 } };
const r = shallowRef(obj);

// 1. 访问 r.value 时,返回的就是原始对象 obj(未被深度代理)
// 2. 当你修改 r.value = newObj 时,会触发依赖更新
// 3. 如果你直接修改 r.value.b.c = 3,Vue 不会检测到,也不会触发依赖更新

5.2 代码示例

<template>
  <div>
    <h3>shallowRef 示例</h3>
    <p>浅层对象:{{ rObj }}</p>
    <button @click="updateNested">修改内部属性 b.c = 3</button>
    <button @click="replaceObj">替换整个对象</button>
    <p>渲染次数:{{ renderCount }}</p>
  </div>
</template>

<script setup>
import { shallowRef, watchEffect, ref } from 'vue';

const rObj = shallowRef({ a: 1, b: { c: 2 } });
const renderCount = ref(0);

// 在模板里渲染 rObj 会导致依赖收集一次
watchEffect(() => {
  renderCount.value++;
  // 访问 rObj(相当于访问 rObj.value),触发渲染计数
  console.log('当前 rObj:', rObj.value);
});

// 修改内部字段(浅层不代理)
function updateNested() {
  rObj.value.b.c = 3; // Vue 不会检测到,不会 re-render
  console.log('已修改内部 b.c,但没有触发渲染');
}

// 替换整个对象(顶层变化会触发依赖更新)
function replaceObj() {
  rObj.value = { a: 10, b: { c: 20 } }; // 触发渲染
  console.log('已替换整个对象,触发渲染');
}
</script>

运行逻辑(预期):

  1. 首次加载时会渲染一次 rObjrenderCount = 1
  2. 点击 “修改内部属性”,虽然 rObj.value.b.c 被改为 3,但不触发 watchEffect 中的渲染,renderCount 保持不变。
  3. 点击 “替换整个对象”,rObj.value = … 会触发 watchEffect,renderCount +1。

5.3 内部原理剖析(图解)

┌──────────────────────────────────────────┐
│ shallowRef({ a: 1, b: { c: 2 } })         │
└────────────────┬─────────────────────────┘
                 │ 创建一个 ShallowRef 对象
  ┌──────────────▼──────────────┐
  │ ShallowRefImpl {            │
  │   __v_isRef: true           │
  │   _dirty: true              │
  │   // value 指向原始对象     │
  │   _value: { a:1, b:{ c:2 }}  │  <-- 这是原始对象,无 Proxy
  │   effect: 对应依赖收集容器    │
  │ }                            │
  └──────────────┬──────────────┘
                 │ 访问 r.value 时,收集 effect
  ┌──────────────▼──────────────┐
  │ 模板或 watchEffect() 中访问  │
  │ console.log(rObj.value)      │
  └──────────────┬──────────────┘
                 │ 如果执行 rObj.value = newObj,则触发 effect
  ┌──────────────▼─────────────────────────┐
  │ 替换顶层对象 newObj 时,触发 ShallowRefImpl.trigger() │
  │ —— watchEffect 或模板重新渲染 ——     │
  └─────────────────────────────────────────┘
  • 获取(get)行为: 只对 .value 本身做依赖收集。
  • 设置(set)行为: 只有当你给 r.value 整体赋新的对象/值时,才会触发依赖更新。
  • 内部嵌套对象 b: { c: 2 } 未被代理,直接就是普通对象,访问或修改时不会触发 Vue 的响应式系统。

5.4 使用场景与注意事项

  • 使用场景:

    1. “只关心整体替换”:比如缓存了一份外部传入的第三方对象,仅需在整个对象换成新引用时触发视图更新。
    2. 大型深度嵌套对象,不想为其内部每一层都做响应式代理,只需某些顶层属性变化时渲染。
    3. 逐步迁移:从普通对象快速升级为响应式状态时,先用 shallowRef 保证最外层可控。
  • 注意事项:

    1. 不会拦截内部字段修改,如果你误以为浅层 Ref 会对嵌套对象生效,可能会导致界面无法更新。
    2. 如果想对内部某些字段做响应式,可手动把内部对象包裹成 reactiveref
    3. 在模板里直接写 {{ rObj.b.c }} 时,仍然是访问原始对象 b,不会触发响应式。

shallowReactive 详解

6.1 基本概念与语法

import { shallowReactive } from 'vue';
  • shallowReactive(object) 会返回一个 Proxy 实例,对传入的 object 顶层属性进行拦截(get/ set),但不会递归地将 object 的嵌套对象做响应式转换。

示例:

const state = shallowReactive({ x: 1, nested: { y: 2 } });

// 访问 state.x:触发依赖收集
// 修改 state.x:触发依赖更新

// 访问 state.nested:读取的是原始对象 { y: 2 }(未代理)
// 修改 state.nested.y:Vue 无法检测,无法触发依赖更新

6.2 代码示例

<template>
  <div>
    <h3>shallowReactive 示例</h3>
    <p>state.x: {{ state.x }}</p>
    <p>state.nested.y: {{ state.nested.y }}</p>
    <button @click="updateX">修改 x</button>
    <button @click="updateNestedY">修改 nested.y</button>
    <p>渲染次数:{{ renderCount }}</p>
  </div>
</template>

<script setup>
import { shallowReactive, watchEffect, ref } from 'vue';

const state = shallowReactive({ x: 1, nested: { y: 2 } });
const renderCount = ref(0);

// 依赖 state.x 和 state.nested.y
watchEffect(() => {
  renderCount.value++;
  console.log('state.x:', state.x, 'nested.y:', state.nested.y);
});

// 修改顶层 x
function updateX() {
  state.x += 1; // 触发渲染
  console.log('已修改 state.x');
}

// 修改嵌套属性 nested.y
function updateNestedY() {
  state.nested.y += 1; // 不触发渲染(nested 未被代理)
  console.log('已修改 state.nested.y,但不会触发渲染');
}
</script>

运行逻辑(预期):

  1. 首次加载时,watchEffect 访问 state.xstate.nested.y,触发一次渲染,renderCount = 1
  2. 点击 “修改 x” 时,state.x 变化,触发 watchEffectrenderCount = 2
  3. 点击 “修改 nested.y” 时,Vue 无法检测到 nested 对象内部修改,不会触发 watchEffectrenderCount 保持不变。

6.3 内部原理剖析(图解)

shallowReactive({ x:1, nested: { y:2 } })
└─> 创建一个 Proxy 对象,handler 只拦截第一层属性

┌───────────────────────────────────────────┐
│ Proxy(                                             │
│   target: { x:1, nested:{ y:2 } },                 │
│   handler: {                                        │
│     get(target, key) {                             │
│       // 访问顶层属性时收集依赖                    │
│       return Reflect.get(target, key)              │
│     },                                              │
│     set(target, key, newVal) {                      │
│       // 修改顶层属性时触发依赖                     │
│       return Reflect.set(target, key, newVal)       │
│     }                                               │
│   }                                                 │
│ )                                                   │
└───────────────────────────────────────────┘
   ↑                   ↑
   │                   └─ 访问/修改 “nested” 只是拿到原始对象,没有做递归代理
   │
   └─ 访问/修改 “x” 时:收集/触发依赖
  • Proxy handler 只拦截第一层,访问或更改 state.x 时,会依次执行 get/set,并进行依赖收集或触发。
  • 访问 state.nested:直接拿到原始对象 { y: 2 },Vue 不会为其创建新的 Proxy,也不会收集与触发依赖。

6.4 使用场景与注意事项

  • 使用场景:

    1. 顶层字段变化触发视图时足够,无需对子属性再做局部响应式。
    2. 数据源来自外部库,不便或不需要修改其内部细节,只想拦截最外层键值。
    3. 避免深度代理带来的递归性能开销,尤其在大型对象场景下。
  • 注意事项:

    1. 凡是访问或修改 nested 内部字段时,均不会触发 Vue 的响应式系统。
    2. 如果你需要在某个属性值变化时,对其内部某个字段进行响应式拦截,需手动对该字段做 reactive 或再包装一层 shallowReactive/reactive
    3. 在模板中取 {{ state.nested.y }},会正常显示 y 的最新值,但当 nested.y 改变时,模板不会重新渲染,除非你重新给 state.nested = {...}(顶层重新赋值)或触发对 nested 的引用更改。

shallowReadonly 详解

7.1 基本概念与语法

import { shallowReadonly } from 'vue';
  • shallowReadonly(object) 会返回一个 Proxy,与 readonly(object) 类似,但只对传入对象的顶层属性进行“只读”保护,对内部嵌套对象不作递归处理。
  • 差异在于: 当尝试修改顶层属性时,会发出警告;但修改嵌套属性时不会被拦截,依然可以成功赋值,不会提示只读错误。

示例:

const data = shallowReadonly({ a: 1, nested: { b: 2 } });

// 访问 data.a:正常读取
// 修改 data.a = 2:会在开发模式下 console.warn(“Set operation failed: target is readonly.”)
// 访问 data.nested:得到原始对象 { b:2 }(未被递归只读包装)
// 修改 data.nested.b = 3:没有只读保护,内部数据实际上被修改了

7.2 代码示例

<template>
  <div>
    <h3>shallowReadonly 示例</h3>
    <p>data.a: {{ data.a }}</p>
    <p>data.nested.b: {{ data.nested.b }}</p>
    <button @click="modifyATop">尝试修改 data.a</button>
    <button @click="modifyNestedB">修改 data.nested.b</button>
    <p>注意:控制台将输出警告或正常修改</p>
  </div>
</template>

<script setup>
import { shallowReadonly, ref } from 'vue';

const data = shallowReadonly({ a: 1, nested: { b: 2 } });

function modifyATop() {
  data.a = 10; // 顶层只读,会在控制台输出警告
  console.log('尝试修改 data.a=', data.a);
}

function modifyNestedB() {
  data.nested.b = 20; // 嵌套对象没有被只读保护,可以正常修改
  console.log('已修改 data.nested.b=', data.nested.b);
}
</script>

运行逻辑(预期):

  1. 点击 “尝试修改 data.a” 时,Vue 会在控制台输出警告,data.a 保持原始值 1
  2. 点击 “修改 data.nested.b” 时,data.nested.b 可以成功被赋值为 20,并且模板也会立刻展示为 20(因为对嵌套对象不是只读或响应式拦截,仅仅是普通对象,所以修改后在模板里渲染时会实时读取最新值)。

7.3 内部原理剖析(图解)

shallowReadonly({ a:1, nested:{ b:2 } })
└─> 创建一个 Proxy,仅处理第一层属性的 set 操作

┌──────────────────────────────────────────┐
│ Proxy(                                         │
│   target: { a:1, nested:{ b:2 } },               │
│   handler: {                                      │
│     get(target, key) {                           │
│       return Reflect.get(target, key)            │
│     },                                            │
│     set(target, key, value) {                     │
│       // 尝试修改 a,会发出只读警告,返回 false     │
│       // 修改 nested,则由于 handler 只拦截第一层, │
│       // Reflect.set 操作依然会被执行             │
│       console.warn('Set operation failed: target is readonly.') │
│       return false;                               │
│     }                                             │
│   }                                               │
│ )                                                 │
└──────────────────────────────────────────┘
   ↑                   ↑
   │                   └─ 当 key = "nested" 时,set 操作会被 Reflect.set 执行
   │                     (Vue 默认开发模式下只在顶层抛出警告,但不阻止嵌套对象修改)
   └─ 当 key = "a" 时,触发只读警告,返回 false,阻止赋值
  • 访问(get):和普通对象一致,不拦截二级访问。
  • 修改顶层属性(set):拦截并发出警告(开发模式)、返回 falsestrict 模式下可能会抛错)。
  • 修改嵌套属性:因为 handler 只对第一层属性 key 做 set 拦截,实际修改会直接调用底层的原始对象赋值,不会被阻止,也不会触发警告。

7.4 使用场景与注意事项

  • 使用场景:

    1. 保护状态顶层字段 不被误改,特别是在组件之间需要只允许读取但不允许修改的场景。
    2. 配置对象:顶层字段决定业务逻辑走向,而嵌套字段可以允许自由修改。
    3. 第三方传入只读要求:有时候库希望暴露一个只读面向外部的对象,但内部属性依然可以由开发者自行修改。
  • 注意事项:

    1. 只对顶层生效,若你误以为整个对象都“只读”,会导致异常:深层属性仍然可写。
    2. 在严格模式(use strict)下,Vue 会在修改顶层属性时抛出错误,而不是仅仅警告。
    3. 如果需要深度只读,还是要使用普通的 readonly,它会递归对所有层级都保护。

综合示例:三种浅层 API 联合使用

下面,我们通过一个综合示例,模拟一个“浅层缓存 + 浅层状态 + 浅层配置”场景,演示如何在一个组件里同时使用 shallowRefshallowReactiveshallowReadonly

<template>
  <div>
    <h2>综合示例:浅层 API 联合使用</h2>

    <!-- 1. shallowRef:缓存异步数据 fetchedData -->
    <div>
      <h3>shallowRef(异步缓存示例)</h3>
      <button @click="fetchData">Fetch Data</button>
      <div v-if="fetchedData">
        <p>fetchedData === rawData: {{ fetchedData === rawData }}</p>
        <p>fetchedData.id: {{ fetchedData.id }}</p>
        <p>fetchedData.nested.value: {{ fetchedData.nested.value }}</p>
        <button @click="modifyFetchedNested">尝试修改 fetchedData.nested.value</button>
        <p>修改后 fetchedData.nested.value: {{ fetchedData.nested.value }}</p>
      </div>
    </div>

    <hr />

    <!-- 2. shallowReactive:只对顶层 properties 处理 -->
    <div>
      <h3>shallowReactive(顶层追踪示例)</h3>
      <p>state.count: {{ state.count }}</p>
      <p>state.nested.msg: {{ state.nested.msg }}</p>
      <button @click="state.count++">state.count++</button>
      <button @click="state.nested.msg = '已修改'">修改 state.nested.msg</button>
    </div>

    <hr />

    <!-- 3. shallowReadonly:顶层只读示例 -->
    <div>
      <h3>shallowReadonly(顶层只读示例)</h3>
      <p>config.apiUrl: {{ config.apiUrl }}</p>
      <p>config.options.flag: {{ config.options.flag }}</p>
      <button @click="tryModifyApiUrl">尝试修改 config.apiUrl</button>
      <button @click="config.options.flag = !config.options.flag">修改 config.options.flag</button>
    </div>
  </div>
</template>

<script setup>
import { shallowRef, shallowReactive, shallowReadonly, ref } from 'vue';

// === 1. shallowRef:模拟异步获取“大对象”然后缓存 ===
// 假设 rawData 是一个从后端获取的深度嵌套对象
const rawData = { id: 100, nested: { value: '初始' } };
// 用 shallowRef 来缓存 rawData
const fetchedData = shallowRef(null);

function fetchData() {
  // 模拟异步 fetch
  setTimeout(() => {
    fetchedData.value = rawData; // 顶层赋值触发响应式
  }, 500);
}

function modifyFetchedNested() {
  if (fetchedData.value) {
    // 由于是 shallowRef,fetchedData.value.nested.value 直接修改,但不触发任何响应式
    fetchedData.value.nested.value = '浅层修改';
  }
}

// === 2. shallowReactive:只对顶层属性追踪 ===
const state = shallowReactive({
  count: 0,
  nested: { msg: '原始消息' }
});
// count 变化时会触发视图更新,nested.msg 变化则不会

// === 3. shallowReadonly:顶层属性只读,嵌套属性可写 ===
const config = shallowReadonly({
  apiUrl: 'https://api.example.com',
  options: { flag: false }
});

function tryModifyApiUrl() {
  // 尝试修改顶层字段 apiUrl,会触发只读警告,且值保持不变
  config.apiUrl = 'https://evil.example.com';
}
</script>

示例解析:

  1. shallowRef 场景:

    • fetchedData 初始为 null,点击 “Fetch Data” 后 500ms 将 rawData 赋给 fetchedData.value,触发视图更新。
    • 点击 “尝试修改 fetchedData.nested.value”,会将 rawData.nested.value 修改为 '浅层修改',但由于是浅层 Ref,模板中 不会 自动刷新 nested.value
    • 你可以在控制台验证:fetchedData.value.nested.value 实际上被改了,但模板未重新渲染。
  2. shallowReactive 场景:

    • state.count 改变时,Vue 能检测到并触发重新渲染。
    • state.nested.msg 改变时,Vue 无法检测到,也不会重新渲染该节点,因为 nested 对象未做深度代理。
  3. shallowReadonly 场景:

    • 顶层字段 config.apiUrl 是只读,tryModifyApiUrl 会在控制台输出警告,但 config.apiUrl 保持原始值。
    • 嵌套属性 config.options.flag 非顶层,仍然可以被正常修改,模板也会实时显示最新值。

常见误区与解答

  1. 误区:shallowRef 会对子属性做响应式

    • 实际情况:shallowRef 只对 .value 本身做响应式,内部属性不代理。若需要对子属性做响应式,请手动将子属性包装为 refreactive
  2. 误区:shallowReactive 会阻止对内部对象的修改触发视图,但无法直接感知或警告

    • 实际情况:shallowReactive 根本不会给嵌套对象套 Proxy,在代码里直接修改 nested 内部时,不会触发视图,也不会抛出警告或错误。植入 watch 时也感知不到内部变化。
  3. 误区:shallowReadonly 能够保证整个对象只读,子属性无法修改

    • 实际情况:shallowReadonly 仅拦截一级字段的 set 操作,对二级及以下字段不做任何拦截。内部仍然是普通对象,可以随意修改。
  4. 误区:使用“浅层”就不会影响性能

    • 实际情况:浅层 API 能减少递归开销,但依然需要对顶层做 Proxy,依赖收集与触发也存在成本。如果项目本身数据量中等(几 MB 以下),普通 reactive 性能已经足够好,削减深度代理的优势可能并不显著。
  5. 误区:浅层 API 会将嵌套对象提升为非响应式

    • 实际情况:浅层 API 只是不再对嵌套对象做 Proxy,但如果嵌套对象本身是通过 reactive / ref 创建的,那么它仍然是响应式。
    const nestedReactive = reactive({ y: 2 });
    const state = shallowReactive({ nested: nestedReactive });
    // state.nested 指向已响应式的 nestedReactive
    // 改变 nestedReactive.y 时,会触发视图更新
    // 但如果 nested 直接是普通对象,则内部字段不会被代理

总结

  • shallowRef:

    • 只拦截顶层 .value 的读写,内部对象不做深度响应式代理。
    • 适用于“只关心整体替换是否变化”的场景。
  • shallowReactive:

    • 只对对象最外层属性做 Proxy,内部嵌套保留为普通对象。
    • 适用于“只需粗略感知顶层字段变化”、且想减少深度递归开销的场景。
  • shallowReadonly:

    • 只对顶层字段做只读保护,内部嵌套对象依然可写。
    • 适用于“顶层配置或状态禁止修改,嵌套字段可自由变更”的场景。

在实际项目中,当你的状态对象非常庞大或深度嵌套,并且对内部字段的响应式需求不高时,使用浅层响应式 API 可以大幅降低代理、依赖收集的开销,同时在写法上更加直观。如果你需要对子属性进行精细化追踪,仍然可以将内部对象再手动做 reactiveref 包裹,从而兼顾性能与灵活性。

希望这篇《Vue 3 浅层响应式 API 全解析:shallowRef、shallowReactive 与 shallowReadonly 深度探索》能让你在理解“浅层响应式”概念、掌握 API 用法、并结合实际应用场景上更加游刃有余。祝你在 Vue 3 的响应式世界里,写出性能与可维护并存的高质量代码!

VUE
最后修改于:2025年05月31日 12:19

评论已关闭

推荐阅读

DDPG 模型解析,附Pytorch完整代码
2024年11月24日
DQN 模型解析,附Pytorch完整代码
2024年11月24日
AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日