vue3 分析总结响应式丢失问题原因(二)

上一篇文件理解了响应式对象应用原理了。公式:

响应式对象 = 代理 + 触发器。

真实的对象:指的是就是一个普通的Object对象,类似{a: 1}

代理对象:Vue定义的特殊对象。类似ref、reactive、computed、props等对象。

但是实际使用结果和预期还是不一致。具体现象是数据修改了,但是并没有实现响应式更新界面。即出现了响应式丢失现象。

一、什么情况下对象的响应式会丢失?

一般网络上查资料,都是告诉我们常见的某些操作(如解构、替换)中容易丢失响应性。只是笼统的说一下容易丢失,具体为什么丢失,会举例哪些情况会丢失,说一堆,感觉把所有情况都告诉你了,又感觉好像还缺点什么。我总结了一下,好像就是缺了一点抽象概况的总结。

所以我先说结论:造成响应式丢失的原因就是没有正确的获取到代理对象。

替换对象时丢失

首先比较简单一点,就是替换操作。例子:

let state = reactive({ count: 0 });
state = { count: 1 }; // 新对象没有响应性

进行替换操作时,可能新的值是一个实际的对象,而不是响应式对象,导致变量引用对象发送了改变,实际结果就是state响应性丢失了。这种情况比较好理解的,注意一点就好了。

解构对象时丢失

比如容易出问题的地方是解构操作。后端程序员可能对于解构概念不是很清晰,理解其语法糖本质后,后面就好理解了。

解构的基本概念

解构是一种从数组或对象中提取值的语法。它允许你将数组或对象的属性直接赋值给变量。

普通数组解构 和 等价的js代码

const arr = [1, 2, 3];
const [a, b, c] = arr; // 解构数组
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
const arr = [1, 2, 3];
const a = arr[0]; 
const b = arr[1]; 
const c = arr[2]; 
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3

普通对象解构 和 等价的js代码

const obj = { name: "Alice", age: 25 };
const { name, age } = obj; // 解构对象
console.log(name); // "Alice"
console.log(age); // 25
const obj = { name: "Alice", age: 25 };
const name = obj.name; 
const age = obj.name; 
console.log(name); // "Alice"
console.log(age); // 25

阶段总结,解构就是一个语法糖,和普通js赋值操作没什么区别。 

reactive对象解构

这个要分为两种情况:

第一种,如果解构的属性值是原始值类型,那么返回的值就是一个真实对象,而不是代理对象,即返回的值丢失了响应性。

在 JavaScript 中,原始值(Primitive Values) 是最基本的数据类型,它们不是对象,也没有方法或属性。JavaScript 有以下 7 种原始值数据类型:

number(数字)、string(字符串)、boolean(布尔值)、undefined(未定义)、

Vue 3 中,子组件响应式数据丢失是一个常见的问题,尤其是在处理 `props` 或解构响应式对象时。这个问题通常表现为在子组件中对 `props` 的某些操作后,数据的响应性丢失,导致视图无法正确更新。 ### 响应式数据丢失原因 Vue 3 使用 `Proxy` 和 `reactive` 来实现响应式系统。然而,在某些情况下,响应式数据的依赖追踪可能会中断。例如,当从 `props` 中解构出一个值时,该值会失去响应性,因为它不再是原始 `props` 对象的一部分。此外,如果在子组件中直接使用 `props` 的某个属性而不通过 `watch` 或 `computed` 等机制进行追踪,也可能导致响应性丢失。 ### 解决方案 #### 使用 `toRef` 或 `toRefs` 当需要从一个响应式对象中提取单个属性时,可以使用 `toRef` 函数来保持响应性。对于多个属性,则可以使用 `toRefs` 函数。 ```javascript import { reactive, toRef } from &#39;vue&#39;; const state = reactive({ a: 1, b: 2 }); // 使用 toRef 保持响应性 const aRef = toRef(state, &#39;a&#39;); ``` #### 使用 `watchEffect` 或 `watch` 在 `<script setup>` 语法中,可以通过 `watchEffect` 来追踪 `props` 中的值,确保它们的响应性。 ```vue <script setup> import { watchEffect } from &#39;vue&#39;; const { count } = defineProps([&#39;count&#39;]); watchEffect(() => { // referencing a destructured binding in tracking contexts // registers it as a dependency. // this will log every time the count prop changes from parent console.log(count); }); </script> ``` #### 使用 `computed` 属性 通过创建计算属性,可以确保即使是从 `props` 解构出来的值也能保持响应性。 ```javascript import { computed } from &#39;vue&#39;; export default { props: [&#39;aReactive&#39;], setup(props) { const aComputed = computed(() => props.aReactive); return { aComputed }; } }; ``` #### 避免直接解构 `props` 尽量避免直接解构 `props`,而是直接访问 `props` 上的属性。这样可以确保 Vue响应式系统能够正确地追踪依赖。 ```javascript // 不推荐的做法 const { aReactive } = props; // 推荐的做法 const aReactive = computed(() => props.aReactive); ``` 通过上述方法,可以在很大程度上避免 Vue 3 子组件中的响应式数据丢失问题。确保在处理响应式数据时,始终使用 Vue 提供的响应式 API 来维护数据的响应性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值