Vue.js。子组件中的变异道具不会触发警告。想知道为啥

Posted

技术标签:

【中文标题】Vue.js。子组件中的变异道具不会触发警告。想知道为啥【英文标题】:Vuejs. Mutating prop in child component does not trigger warning. Wondering whyVue.js。子组件中的变异道具不会触发警告。想知道为什么 【发布时间】:2021-03-10 05:39:20 【问题描述】:

我注意到 prop 突变 (Vue 2.6) 有一些奇怪的地方。

应避免直接在子组件中修改 props,否则会触发以下著名警告

"避免直接改变一个 prop,因为它的值是 被覆盖了……”

所以如果在我的父组件中我有一个类似的数据

exemple: "Hello World"

我作为道具传递给子组件。如果在那个子组件中我做类似的事情

this.exemple = "Hello World!"

我收到警告。很公平。现在我注意到如果父级中的数据是像

这样的对象
exemple : message : "Hello World"

在孩子身上我会做类似的事情

this.exemple.message = "Hello World!"

这不会触发任何警告,而且父组件中的数据会更新

我想知道为什么。为什么 prop 突变在一种情况下会传播到父级,而在另一种情况下不会传播到父级?它可能与javascript如何存储这些变量有关吗?使用这个技巧是个好习惯吗?

【问题讨论】:

您可以发出更改 this.$emit('update:example', 'Hello!') ... 并在父同步中 :example.sync="example" ... 这样 vue 就会知道更改并可以执行任何需要的响应操作 【参考方案1】:

因为突变预防只捕获对道具的直接分配 - 它不会捕获对其属性的操作。这个想法是,如果您为道具分配新值 - 您将分配给prop,而不是分配给位于提供道具的父 Vue 组件中的变量。

一旦父组件中的某些内容更新了 feed 变量 - prop 将使用这个新值进行更新,并且您分配给子组件中 prop 的值将被覆盖。

如果你给 props 提供一个对象,然后在你的子组件中改变 prop 内的属性 - 它会影响父组件内的同一个对象。但是,如果您尝试为子组件中的 prop 分配一个新对象 - 您应该会收到关于 mutating props 的相同警告。

【讨论】:

【参考方案2】:

为什么 prop 突变在一种情况下会传播到父级,而在另一种情况下不会传播?它可能与javascript如何存储这些变量有关吗?

是的。 JavaScript reference 变量(例如对象和数组)在您改变它们的属性/值时不会改变它们的引用。这意味着父级也可以访问更改的属性,因为它也可以访问引用。并且 Vue 只有在引用发生变化时才会给出 prop 突变警告。

警告:

this.prop = 

没有警告:

this.prop.id = 5

使用这个技巧是个好习惯吗?

没有。又回到了违反One way data flow 的问题,其中数据通过道具向下传递(到孩子)并通过事件向上传递(到父母)。


好的,但为什么 Vue 不警告这些变化?

考虑一个有 1000 个属性的对象或一个有 1000 个项目的数组。 Vue 必须深入检查所有 1000 个更改,并且没有快速的方法可以做到这一点,因为每个项目都必须单独与旧值进行比较。这会对性能产生影响,并可能使许多应用程序无法使用。


这是来自 Vue 团队成员Bolerodan 的comment:

通常你不应该那样做。这可能/可能会导致代码中出现意外错误。通常,您应该复制您的对象,对其进行修改,然后向上发送到父对象(我相信正如您在上一段中提到的那样)。这是我采用的方法,也是自上而下、自上而下的普遍共识。

【讨论】:

【参考方案3】:

一个非常简单的答案是,您正在改变 reference value,而 Vue 不会跟踪整个 reference,而是只检查引用所在的地址。因此,如果您重新分配该值,那么它会警告您。

理解行为的一个很好的例子是通过变量声明来理解const

const 使您的变量不可变,但同样适用于它,如果该值本质上是 primitive,则您无法更改它,但如果它是 reference,则您无法更改它,但您绝对可以更新位于reference的值

const a = 'Foo' // Primitive value

a = 'bar' // voilation
 
const b =  // Reference value
 name: 'Foo' 


b.name = 'Bar' // It's good

console.log(b)

b =  // re-assign is voilation

【讨论】:

以上是关于Vue.js。子组件中的变异道具不会触发警告。想知道为啥的主要内容,如果未能解决你的问题,请参考以下文章

当根组件中的值更改时,子组件中的 Vue.js props 值不会更新

Vue js 子组件中未定义的道具。但仅在其脚本中

Vuex 全局状态更改不会触发 Nuxt 中 v-for 循环中的重新渲染组件

道具被变异(在 django 模板和带有 CDN 的 Vue.js 中)

将 axios 中的道具传递给 Vue.js?

将父母道具传递给Vue,js中的插槽