那么 Vue.set 到底是什么?数据与响应式 陷阱 实际使用 Vue.set Vue 3.0

2025-06-07

那么 Vue.set 到底是什么?

数据和反应性

陷阱

实际上使用 Vue.set

Vue 3.0

本文最初发表于https://www.telerik.com/blogs/so-what-actually-is-vue-set


谈论的Vue.set是反应性,所以准备好一些理论知识吧。不过,一如既往,它并不需要太难或无聊。准备好牛油果和薯片,做些牛油果酱,我们就开始吧。

数据和反应性

每当您在 Vue 组件内创建data()属性函数并返回对象时,Vue 都会在后台做很多事情来将所有内容连接到组件内并使其具有响应性。

export default {
  data() {
   return {
     red: 'hot',
     chili: 'peppers'
   }
  }
}

Vue 首先会处理我们这些 RHCP 数据,它会遍历每个对象propertiesreturn { }并为每个对象创建一个唯一的gettersetter。至于具体实现细节,本文不做赘述,不过Vue Mastery有一个很棒的视频,详细解释了这一点。

创建这些的目的是,当您在代码中访问这些属性时,this.red例如,通过执行操作,或者当您设置它们时,this.red = "hotter"您实际上是在调用这些getters并且setters是 Vue 为您创建的。

在这个神奇的 SETGET 土地上,Vue 将您的计算机属性、观察者、道具、数据等连接起来reactive,用非常简单的术语来说,就是每次更改 setter 时都会调用一个更新整个过程的函数。

陷阱

太棒了!这正是我们喜欢 Vue 的原因,它惊人的响应速度和强大的底层功能。但它也有一个需要探索的阴暗面。

让我们稍微改变一下数据,看看当我们开始尝试处理动态数据时会发生什么。

data() {
  return {
    members: {}
  }
}

好了,目前为止没什么特别的,我们有一个members数据属性,我们想在其中添加乐队成员的信息。现在为了举例,我们添加一个方法,假装从远程 http 调用中提取一些信息,并返回一个包含乐队信息的 JSON 对象。

data() {
  return {
    members: {}
  }
},
methods: {
  getMembers() {
   const newMember = {
     name: 'Flea',
     instrument: 'Bass',
     baeLevel: 'A++'
   }; // Some magical method that gives us data got us this sweet info

   // ...
  }
}

嗯。好吧,看看这个例子,我们停下来思考一下。有很多方法可以解决当前的困境,我们如何将这个newMember对象添加到我们当前的members属性中?

也许您正在考虑让我们将其变成members一个数组push,当然,但这是作弊,因为它破坏了我精心构建的示例,而这个示例并不是我在输入此代码时编造的。

在这种情况下,我们需要members一个对象。好吧,很简单——你可能会说,干脆给这个members属性添加一个新属性吧,毕竟它是个对象。实际上,我们直接把成员的名称作为属性的名称就行了。

getMembers() {
   const newMember = {
     name: 'Flea',
     instrument: 'Bass',
     baeLevel: 'A++' // Totally important property that we will never use
   }; // Some magical method that gives us data got us this sweet info

   this.members[newMember.name] = newMember;
  }

洛克塔·奥加尔!

但事实并非如此,因为 A. 这不是奥格瑞玛,B. 我们现在遇到了问题。

如果您现在在浏览器上运行此代码并进行测试,您将看到您实际上正在将这些新数据推送到members数据中,但是对组件状态的这种更改实际上不会使您的任何应用程序重新渲染。

在您仅将这些数据用于某些计算或某种类型的内部存储的情况下,这样做不会影响您的应用程序 - 但是,这是一个巨大的问题,如果您在应用程序上被动地使用这些数据在页面上显示某些信息,或者进行条件渲染,v-if那么v-else事情就会变得很奇怪。

实际上使用 Vue.set

现在我们了解了问题的根源,就可以找到正确的解决方案了。请允许我向大家介绍Vue.set

Vue.set是一个工具,它允许我们向已经响应式的对象添加新属性,并确保该新属性也具有响应式。这完全解决了我们在另一个示例中遇到的问题,因为当我们的新属性被设置时members,它将自动挂接到 Vue 的响应式系统中,并在后台运行所有酷炫的 getter/setter 和 Vue-magic。

不过,需要注意一点,才能理解这会如何影响数组。到目前为止,我们只真正地接触了对象,它们非常容易理解。新的 prop?如果你想让它具有响应式,可以使用 Vue.set 添加。很简单。

按照我们的例子,让我们改变Vue.set一下用法。

getMembers() {
   const newMember = {
     name: 'Flea',
     instrument: 'Bass',
     baeLevel: 'A++'
   }; // Some magical method that gives us data got us this sweet info

   //this.members[newMember.name] = newMember;
     this.$set(this.members, newMember.name, newMember);
  }

这是新的this.$set(this.members, newMember.name, newMember);

关于这段代码,我想提两点。到目前为止,我一直告诉你Vue.set我们将要这样做,但现在我正在使用this.$set,但不用担心——这只是一个别名,所以它的工作方式和行为方式完全相同。更酷的是,你不必在组件中导入 Vue 即可使用它。

我想指出的第二件事是这个函数的语法。它需要三个参数,分别是object或 ,array也就是我们要修改的那个(在本例中是this.members)。

第二个参数指向我们传递的第一个对象/数组(property因为我们希望它是动态的)。keynewMember.name

最后是第三个参数,即我们想要设置的值。(在我们的例子中是newMember)。

         this.members [newMember.name] = newMember;
//            V               V              V
this.$set(this.members, newMember.name,   newMember);

(PS:我的 ASCII 技能不出售^)

但是数组反应性怎么样?

当我们在初始状态中创建一个时array,Vue 会将其设置为响应式,但是 Vue 目前无法检测到你使用索引直接赋值的情况。例如,如果我们这样做:

this.membersArray[3] = myNewValue;

那么 Vue 将无法检测到此更改,因此它不会具有响应性。请记住,如果您使用诸如pop、之类的操作修改数组splicepush则这些操作将触发数组的响应性,因此您可以安全地使用这些操作。

在需要直接设置索引值的情况下,我们必须Vue.set提供帮助。让我们看看在前面的例子中是怎样的。

this.$set(this.membersArray, 3, myNewValue)

如果你想了解有关所有反应性警告的更多信息,请查看此官方文档链接

Vue 3.0

在撰写本文时,这些内容仍有可能发生变化,但坊间传言称,这些警告将不再是问题。换句话说,在 Vue 3.0 中,你可以完全忘记这些边缘情况,除非那些可怜的家伙仍然需要针对一些无法完全支持新响应式系统的旧浏览器。

文章来源:https://dev.to/marinamosti/so-what-actually-is-vue-set-5afi
PREV
Understanding the Spread Operator in JavaScript Diving in Merging Making copies
NEXT
Vue.js 初学者入门(第四部分)v-for 更上一层楼 如果我不需要包裹 DIV 怎么办?:key 属性 最终代码挑战