gpt4 book ai didi

javascript - Vue 组件的 prop 设置为实例数据会改变上游值

转载 作者:行者123 更新时间:2023-12-02 22:59:38 26 4
gpt4 key购买 nike

我在这里看到了一些意想不到的奇怪行为,但就纯 JavaScript 而言,它对我来说是直观的。

我有一个表单 Controller ,它累积一个 this.thing 对象,该对象在最终提交时发送到服务器。这是一个多步骤表单,因此每个步骤都会向 this.thing 添加一些数据。

所以 Controller 有:

data() {
return {
thing: {},
};
},

此 Controller 的 DOM 标记有一个子项,例如:

<a-child
:initial-thing="thing"
></a-child>

子进程使用该 prop 来显示其初始状态,因此它接收该 prop 并将其设置为自己的本地状态作为实例数据:

initialThing: {
type: Object,
required: true,
},

...

data() {
return {
thing: this.initialThing,
};
},

然后这个 child 有一个像这样的复选框:

<a-checkbox
v-model="thing.field"
:initial-value="initialThing.field"
></a-checkbox>

这一切都工作正常,只是我刚刚注意到当复选框更改时,它会改变父 Controller thing.field 值。

我提出这个问题是因为我不明白 Vue 如何做到这一点,对我来说唯一有意义的是当 child 做 thing: this.initialThing 时,它是允许子进程调用 this.initialThing 上该字段的 setter 函数。

如果我这样做,它就会停止改变父级的状态:

data() {
return {
thing: { ...this.initialThing },
};
},

在我的实际应用程序中,它更复杂,因为有 2 个中间组件,因此孙子正在改变祖 parent 的状态,这源于我在这里描述的模式。

任何人都可以为这里发生的事情提供教科书式的答案吗?我对是否依赖这种行为犹豫不决,因为驱动它的代码并不明确。它使我的一些 $emit() 事件变得多余,有利于使用这种间接/非显式的向上游发送数据的方式。

还要明确的是,这与 v-model 无关,因为如果我这样做 this.thing.field = 'new value'; 也会这样做。我相信这与继承 this.initialThing 上的 getter/setter 密切相关。依赖这种行为安全吗?如果我依赖它,它将使我的代码更加简洁,但是天真的个人可能很难理解数据如何将其放入祖 parent 组件中。

最佳答案

这是一个浅拷贝,因此您无法阻止突变的孙子。

data() {
return {
thing: { ...this.initialThing },
};
},

解决方案如下:

data() {
return {
thing: JSON.parse(JSON.stringify(this.initialThing)),
};
},

const initialThing = {
age: 23,
name: {
first: "David",
last: "Collins",
}
}

const shallowCopy = { ...initialThing };

shallowCopy.age = 10;
shallowCopy.name.first = "Antonio"; // will mutate initialThing

console.log("init:", initialThing);
console.log("shallow:", shallowCopy);

const deepCopy = JSON.parse(JSON.stringify(initialThing));
deepCopy.age = 30;
shallowCopy.first = "Nicholas"; // will not mutate initialThing

console.log("------Deep Copy------");
console.log("init:", initialThing);
console.log("deep:", deepCopy);

工作原理:

JSON.stringify(this.initialThing)

这会将 JSON Object 转换为 String 类型。这意味着它永远不会再让 child 发生变异。然后 JSON.parse 会将 String 转换为 Object 类型。

But, using stringify and parse will be expensive in performance. :D

更新:如果你使用的是lodash或者可以添加外部库,你可以使用_.cloneDeep .

_.cloneDeep(value); // deep clone
_.clone(value); // shallow clone

关于javascript - Vue 组件的 prop 设置为实例数据会改变上游值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57839858/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com