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(未定义)、

### Vue3 中 `reactive` 对象响应式失效解决方案 #### 正确处理深层嵌套对象的响应式属性 当使用 `reactive` 创建的对象包含深层次嵌套结构时,修改这些内部属性不会自动触发视图更新。为了确保所有层次都能保持响应性,应当始终通过代理对象访问并更改其属性。 ```javascript import { reactive } from 'vue'; const state = reactive({ nested: { value: 0, }, }); // 错误做法:直接替换整个子对象会丢失响应性 state.nested = { ...state.nested }; // 正确做法:仅改变具体字段而不覆盖原有对象 state.nested.value++; ``` #### 避免解构操作符导致响应式丧失 一旦对 `reactive` 返回的结果进行了解构赋值,则新创建出来的变量就不再具备原有的响应特性。因此,在需要保留响应性的场景下不应采用这种方式获取成员变量。 ```javascript const userState = reactive({ username: '' }); // 不推荐的做法——这会使username变成普通的非响应型字符串 let { username } = userState; // 推荐的方式——继续利用proxy机制来间接读取/写入目标属性 console.log(userState.username); userState.username = "newName"; ``` #### 更新数组内容而非整体重置 如果要向由 `reactive()` 构建而成的列表追加项目或移除已有条目,应该调用内置方法如 `.push()`,`.pop()`, 而不是简单地重新分配一个新的数组给它。因为后者相当于替换了原来的引用地址,从而中断了框架对其变化感知的能力。 ```javascript const items = reactive([]); function addItem(item){ // 应该这样增加元素以维持响应行为 items.push(item); /* 或者也可以考虑如下方式 */ //items.splice(items.length, 0, item); } async function fetchItems(){ let fetchedData = await someApiCall(); // 切勿这样做,因为它将破坏现有的反应链路 //items = [...fetchedData]; } ``` #### Vuex Store 的特殊注意事项 在 Vuex store 中定义模块化状态管理逻辑时同样需要注意上述原则的应用。特别是涉及到跨组件通信以及异步加载数据的情况下更需谨慎对待可能引起的问题。 ```javascript export default createStore({ state: () => ({ users: reactive([]) }), mutations:{ updateUserList(state,payload){ payload.forEach(newUser=>state.users.push(newUser)); } }, actions:{ async getUsers(context){ try{ const response=await axios.get('/api/users'); context.commit('updateUserList',response.data); }catch(error){/* handle error */} } } }); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值