Skip to content

一文搞懂vue2、3响应式更新的机制和区别

1.vue2中数据变化了但是视图没有更新,是在什么场景下呢,为什么会有这个问题?

在Vue.js 2中,当数据变化了但视图没有更新的情况通常发生在以下几种场景下:

  1. vue的异步更新机制:Vue.js 的数据绑定是响应式的,但它并不是实时更新的。Vue.js 使用一种称为"异步更新队列"的机制,将多个数据变更操作收集在一起,然后在下一个事件循环中批量执行更新。这意味着在某些情况下,如果你在同一个事件循环中多次修改数据,只会触发一次视图更新。这可能导致你认为数据已经改变,但视图还没有同步更新。

  2. 数据变化的检测问题:Vue.js 的响应式系统依赖于Object.definePropertyProxy来捕获数据的变化。如果你在对象上添加新属性而不使用Vue.set(或者在数组上直接修改索引对应内容而不使用splice等可支持响应式的方法),Vue.js 可能无法检测到这些变化,因此视图不会更新。

  3. 组件生命周期钩子问题:有时,数据变化后视图没有更新可能与组件生命周期钩子有关。如果你试图在created钩子或beforeUpdate钩子中修改数据,可能会导致视图无法及时更新,因为这些钩子在视图更新之前被调用。

  4. 使用非响应式数据如果你将数据设置为冻结状态,例如通过Object.freeze(),那么这些数据的变化(因为根本就无法改变)将不会触发视图更新。

    当你使用 Object.freeze() 来将数据设置为非响应式(冻结状态)时,你在实际中禁止了这些数据对象的属性的修改、添加和删除操作。这就意味着这些对象变得不可变,无法被 Vue.js 的响应式系统追踪和拦截。

    具体来说,使用 Object.freeze() 可以实现以下效果:

    1. 禁止属性修改:一旦一个对象被冻结,你无法通过直接赋值来修改其属性的值。
    2. 禁止属性添加:无法向一个被冻结的对象添加新的属性。
    3. 禁止属性删除:无法从一个被冻结的对象中删除属性。

    这是一个示例,演示如何使用 Object.freeze() 来冻结一个对象:

    js
    const data = {
      name: 'Alice',
      age: 30
    };
    
    // 冻结对象
    Object.freeze(data);
    
    // 尝试修改属性值,但不会生效
    data.name = 'Bob';
    data.age = 31;

    在上面的示例中,Object.freeze(data) 冻结了 data 对象,导致所有属性的修改、添加和删除操作都不会起作用。这是一种用于确保对象不可变性的方法,但需要注意的是,一旦对象被冻结,就无法撤销冻结,也无法再次将其变为可变的。

    注意:如果尝试修改一个已经被冻结的对象的属性,修改操作不会生效,但也不会引发错误。

解决这些问题的方法包括:

  • 在数据变化后,确保使用Vue.setthis.$set来添加新属性或在数组上进行修改,以确保Vue.js能够检测到变化。——> 解决对象/数组的变化检测问题
  • 使用this.$nextTick来确保在视图更新后执行操作,以解决异步更新问题。——> 解决vue的异步更新机制的问题,保证修改数据之后就立马呈现在视图上面!
  • 仔细检查组件生命周期钩子,确保在适当的时机修改数据。
  • 避免使用非响应式数据。

总之,Vue.js的响应式系统通常是可靠的,但在一些特定情况下需要小心处理以确保视图正确更新。查看Vue.js的官方文档和错误消息可以帮助你更好地诊断和解决这些问题。如果遇到困难,可以考虑使用Vue Devtools等工具来调试Vue.js应用程序。

2.vue中数据变化的检测问题及$set用法

1.vue2中数据变化的检测问题(vue2是对象/数组,vue3只有数组的问题)

在vue开发中,我们有时会遇到数据更新视图不更新问题,对象的地址没有改变,vue就监测不到数据变化。这个时候,数据绑定的响应式就失效了。

以下这3种情况,Vue都会检测不到数据的变化

1.当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue (vm 就是 this,即 vue 对象)

2.当你直接修改数组的长度时,例如:vm.items.length = newLength

3.当你进行对象属性的添加或删除时,由于 JavaScript 的限制,Vue不能检测对象属性的添加或删除,例如:obj[a] = “123” 或者 obj.a = “123”;

2.vue中可以让数组实现响应式的方式

其实在正常情况下数组是完全可以响应式的:

数组可以实现响应式的七个方法:push、pop、shift、unshift、split、sort、reverse

为什么这些方法可以?因为Vue对这几个数组的方法进行了劫持(即通过修改原生的数组方法来实现),也就是 vue 默认用这几个函数修改数组是可以检测变化的。

  • push() 可向数组的末尾添加一个或多个元素,并返回新的长度

  • pop() 从数组的尾部删除一个元素,返回删除的元素

  • unshift() 向数组的前面添加元素,返回值:数组的新长度

  • shift() 从数组头部删除一个元素,返回删除的元素

  • splice() 截取数组的一部分,或者增删改查都可以

    • 删除:两个参数,splice(index,num) 删除的第一项的位置以及要删除的项数
    • 添加:三个参数,插入起始位置、删除的项数(为0)、插入的项,向指定位置插入任意数量的项。arr.splice(1,0,"or","ue")
    • 替换:先删除再添加,三个参数:起始位置、删除的项数、要添加的项数。添加的与删除的数量不一定要一致。arr.splice(1,2,"or","ue")
  • sort() 对数组元素进行排序,默认根据字符串Unicode码进行排序,对数字进行排序时参数要传递一个比较函数。

    注意:JavaScript 中的 Array.prototype.sort() 方法会修改原数组。该方法用于对数组的元素进行排序,并将排序后的结果存储在原始数组中,同时也返回排序后的元数组。

js
sortNumber(a,b){
	return a-b
};
  • reverse() 该方法用于颠倒数组中元素的顺序

上面的方法会把原数组更改掉,可以选用这些方法来实现响应式。

不会更改原数组,返回新数组的方法(不能实现响应式):

flter()、concat() 和 slice()。它们不会变更原始数组,而总是返回一个新数组。使用这些方法会造成数据双向绑定失效。

  • filter() 创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
  • concat() 用于连接两个或多个数组。该方法不会改变现有的数组。
  • slice() 可从已有的数组中返回选定的元素,选择从给定的 start 参数开始的元素,并在给定的 end 参数处结束,但不包括。该方法并不会修改数组,而是返回一个子数组。

2.$set的用法

this.$set(原对象/数组,索引值,需要赋的值)

vue中$set解决数据响应式失效:即vue中$set的使用场景

注意:$set方法用于对象或者数组都是可以的!!!

当你利用索引直接设置一个项时(通过下标修改数组),例如:vm.items[indexOfItem] = newValue;

当你给对象新增一个属性时,例如:obj[a] = “123”;

解决:用$set方法

js
this.$set(Object, key, value)
//this.$set(this.list[i],"flag",true)

当你修改数组的长度时,例如:vm.items.length = newLength

解决:vm.items.splice(newLength)

3.vue3中会出现数据变化了但是视图没有更新的问题吗?

注意:依然会,不过对象不会,只有数组会!

在 Vue 3 中,通常不会出现数据变化了但是视图没有更新的问题,因为 Vue 3 采用了更强大和可预测的响应式系统,并且具有更好的性能。Vue 3 的响应式系统使用了 Proxy 代理对象来捕获数据的变化,相对于 Vue 2 的 Object.defineProperty,Proxy 具有更好的性能和更丰富的特性,因此更不容易出现数据变化与视图不同步的问题。——> 重点理解:vue3主要改变的是对象的响应式更新问题,保证了可以直接修改属性或者增加属性不会丢失响应式!(对于数组没有改变)

然而,虽然 Vue 3 改进了响应式系统,但仍然有一些情况可能导致视图没有及时更新,包括:

  1. 异步更新问题:Vue 3 仍然具有异步更新队列的机制,某些情况下可能需要使用 this.$nextTickawait this.$nextTick() 来确保在下一次事件循环中更新视图。
  2. 直接修改数组元素:就像在 Vue 2 中一样,如果你直接修改了数组元素的值而不是使用 Vue 提供的数组方法,可能会导致视图不更新。 ——> 重中之重:数组还是没办法响应式!只能使用7种方法!
  3. 非响应式数据:如果数据不被定义为响应式(例如,使用 Object.freeze()),那么数据的变化将不会触发视图更新。

总之,Vue 3 提供了更稳定和可靠的响应式系统,但仍需要开发人员遵循 Vue 的数据变更规则以确保视图正确更新。阅读 Vue 3 的官方文档可以帮助你更好地理解和处理数据更新问题。