英文:
Why is reactive variable changing when it is not assigned to v-model
问题
我对组合式API还比较新,但到目前为止一切都相对简单。
我正在进行一个返回一些数据的Axios调用:
const transaction = ref({});
let pbl = reactive({});
const getPayByLinkTransaction = () => {
axios({
method: "get",
url: "pay-by-link",
params: {
merchantUuid: import.meta.env.VITE_MERCHANT_UUID,
uuid: route.params.uuid,
},
})
.then((res) => {
transaction.value = res.data;
pbl = res.data;
})
.catch((e) => {
console.log(e);
});
}
getPayByLinkTransaction();
然后我有以下文本字段:
<v-text-field v-model="transaction.reference" variant="solo" class="mb-1"
:rules="config?.fields?.reference?.required ? required : []"></v-text-field>
PBL - {{ pbl.reference }} <br>
Transaction - {{ transaction.reference }}
reference 键一开始包含John Doe。
奇怪的是,当我开始在文本字段中输入时,它会更改transaction和pbl对象中的reference。
由于v-model连接到transaction.reference,它不应该只更改transaction对象中的变量吗?
为什么pbl对象也在改变?
我想要的是两个对象,其中一个包含原始数据,另一个包含如果用户修改了任何细节的修改后的数据。
英文:
I'm fairly new to the composition API but it's been somewhat straight forward so far.
I'm making an Axios call that is returning some data;
const transaction = ref({});
let pbl = reactive({});
const getPayByLinkTransaction = () => {
axios({
method: "get",
url: "pay-by-link",
params: {
merchantUuid: import.meta.env.VITE_MERCHANT_UUID,
uuid: route.params.uuid,
},
})
.then((res) => {
transaction.value = res.data;
pbl = res.data;
})
.catch((e) => {
console.log(e);
});
}
getPayByLinkTransaction();
Then I have the following textfield:
<v-text-field v-model="transaction.reference" variant="solo" class="mb-1"
:rules="config?.fields?.reference?.required ? required : []"></v-text-field>
PBL - {{ pbl.reference }} <br>
Transaction - {{ transaction.reference }}
The reference key contains John Doe to start off with.
What's strange is that when I start typing into the textfield, it's changing reference in both the transaction and pbl object.
As the v-model is attached to transaction.reference, should it not only change the variable in the transaction object?
Why is the pbl object changing too?
What I'm after are two objects where one contains the original data and the other contains modified data if the user were to amend any details.
答案1
得分: 2
以下是您提供的文本的翻译部分:
I was not able to reproduce the problem using Composition API
in both Vue 2 and Vue 2.
无法在Vue 2和Vue 2中使用“Composition API”重现问题。
So, here is my assumption about what's going on.
所以,这是我关于发生了什么的假设。
You are assigning the same object from res.data
to transaction
and to pbl
.
Since it is the same object, the change of reference
over transaction.reference
changes also pbl.reference
您将res.data
中的相同对象分配给transaction
和pbl
。
因为它是相同的对象,所以transaction.reference
上的reference
更改也会更改pbl.reference
。
Here is the simple Vue 2 playground using Options API
to understand the problem.
以下是使用“Options API”创建的简单Vue 2示例,用于理解问题。
The interesting this is, the reactivity in Vue 3 behaves different.
有趣的是,在Vue 3中,响应性行为不同。
The Vue 3 reactive()
function create a Proxy object. Check the Behavior Differences from Vue 3
Vue 3中的reactive()
函数创建一个代理对象。请查看从Vue 3中的行为差异。
英文:
I was not able to reproduce the problem using Composition API
in both Vue 2 and Vue 2.
So, here is my assumption about what's going on.
You are assigning the same object from res.data
to transaction
and to pbl
.
Since it is the same object, the change of reference
over transaction.reference
changes also pbl.reference
Here is the simple Vue 2 playground using Options API
to understand the problem.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const App = {
el: '#app',
data() {
return {
myObj: { id: 1, counter: 0 },
myObjCopy: {}
}
},
methods: {
replaceObj() {
let obj = { id: this.myObj.id + 1, counter: 0 };
this.myObj = obj;
this.myObjCopy = obj;
},
plus() {
this.myObj.counter++;
}
}
}
const app = new Vue(App);
<!-- language: lang-css -->
#app { line-height: 2; }
[v-cloak] { display: none; }
<!-- language: lang-html -->
<div id="app">
<button type="button" @click="replaceObj()">Replace My Object</button><hr/>
My Object Id: {{myObj.id}}<br/>
Counter: {{myObj.counter}}
<button type="button" @click="plus()">+1</button><br/>
<hr/>
My Object Copy Id: {{myObjCopy.id}}<br/>
Counter: {{myObjCopy.counter}}
</div>
<script type="text/javascript" src="https://unpkg.com/vue@2.7.14/dist/vue.min.js"></script>
<!-- end snippet -->
The interesting this is, the reactivity in Vue 3 behaves different.
// true in 2.7, false in 3.x
reactive(foo) === foo;
The Vue 3 reactive()
function create a Proxy object. Check the Behavior Differences from Vue 3
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const { createApp, ref, reactive } = Vue;
const App = {
setup() {
let obj = { id: 1, counter: 0 };
const myObj = ref(obj);
let myObjCopy = reactive(obj);
const plus = () => {
myObj.value.counter++;
}
const replaceObj = () => {
let obj = { id: myObj.value.id + 1, counter: 0 };
myObj.value = obj;
myObjCopy = obj;
}
return { myObj, myObjCopy, plus, replaceObj}
}
}
const app = createApp(App)
app.mount('#app')
<!-- language: lang-html -->
<div id="app">
<button type="button" @click="replaceObj()">Replace My Object</button><br/><br/>
My Object Id: {{myObj.id}}<br/>
Counter: {{myObj.counter}}
<button type="button" @click="plus()">+1</button><br/>
<hr/>
My Object Copy Id: {{myObjCopy.id}}<br/>
Counter: {{myObjCopy.counter}}
</div>
<script type="text/javascript" src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<!-- end snippet -->
答案2
得分: 2
尝试按值复制对象,而不是引用:
const { ref, reactive } = Vue
const app = Vue.createApp({
setup() {
const data1 = ref({})
let data2 = reactive({})
const byReference = { ref: 'reference' }
data1.value = byReference
data2 = byReference
const byValue = { ref: 'value' }
const data3 = ref({})
let data4 = reactive({})
data3.value = byValue
data4 = { ...byValue }
return {
data1, data2, data3, data4
};
},
})
app.mount('#demo')
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<div id="demo">
<input v-model="data1.ref" />
{{data1.ref}}
{{data2.ref}}
<input v-model="data3.ref" />
{{data3.ref}}
{{data4.ref}}
</div>
英文:
Try to copy object by value, not reference:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const {ref, reactive} = Vue
const app = Vue.createApp({
setup() {
const data1 = ref({})
let data2 = reactive({})
const byReference = {ref: 'reference'}
data1.value = byReference
data2 = byReference
const byValue = {ref: 'value'}
const data3 = ref({})
let data4 = reactive({})
data3.value = byValue
data4 = {...byValue}
return {
data1, data2, data3, data4
};
},
})
app.mount('#demo')
<!-- language: lang-html -->
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<div id="demo">
<input v-model="data1.ref" />
{{data1.ref}}
{{data2.ref}}
<input v-model="data3.ref" />
{{data3.ref}}
{{data4.ref}}
</div>
<!-- end snippet -->
答案3
得分: 1
以下是翻译好的部分:
"The main problem here is the understanding of how the Objects are threated in JavaScript."
这里的主要问题是理解JavaScript中如何处理对象。
"const obj1 = { data : { value: 1 } }"
"const obj2 = obj1.data;"
"console.log( obj1.data === obj2 ); // --> true"
"这里是另一个非常简单的示例来演示它。"
"const obj1 = { data : { value: 1 } }"
"console.log(obj1.data.value = ${obj1.data.value}
);"
"// --> obj1.data.value = 1"
"const obj2 = obj1.data;"
"obj2.value++;"
"console.log(obj1.data.value = ${obj1.data.value}
);"
"// --> obj1.data.value = 2"
"console.log(obj1.data == obj2 : ${obj1.data == obj2}
);"
"// --> true"
"// 即使是JavaScript对象的解构赋值也不会断开与原始数据对象的连接"
"const { data } = obj1;"
"data.value++;"
"console.log(obj1.data.value = ${obj1.data.value}
);"
"// --> obj1.data.value = 3"
"// 这有效,因为'value'是按值传递的,而不是引用"
"const obj3 = { value: obj1.data.value }"
"obj3.value++;"
"console.log(obj3.value = ${obj3.value}
);"
"// --> obj3.value = 4"
"console.log(obj1.data.value = ${obj1.data.value}
);"
"// --> obj1.data.value = 3"
"// 另一种方法是使用展开语法"
"const obj4 = {...obj1.data}"
"obj4.value++;"
"console.log(obj4.value = ${obj4.value}
);"
"// --> obj4.value = 4"
"console.log(obj1.data.value = ${obj1.data.value}
);"
"// --> obj1.data.value = 3"
英文:
The main problem here is the understanding of how the Objects are threated in JavaScript.
const obj1 = { data : { value: 1 } }
const obj2 = obj1.data;
console.log( obj1.data === obj2 ); // --> true
Here is another very simple playground to demonstrate it.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const obj1 = { data : { value: 1 } }
console.log(`obj1.data.value = ${obj1.data.value}`);
// --> obj1.data.value = 1
const obj2 = obj1.data;
obj2.value++;
console.log(`obj1.data.value = ${obj1.data.value}`);
// --> obj1.data.value = 2
console.log(`obj1.data == obj2 : ${obj1.data == obj2}`);
// --> true
// even the JavaScript object destructuring assignment
// doesn't break the connection to original data Object
const { data } = obj1;
data.value++;
console.log(`obj1.data.value = ${obj1.data.value}`);
// --> obj1.data.value = 3
// this works, since 'value' is passed by value, not reference
const obj3 = { value: obj1.data.value }
obj3.value++;
console.log(`obj3.value = ${obj3.value}`);
// --> obj3.value = 4
console.log(`obj1.data.value = ${obj1.data.value}`);
// --> obj1.data.value = 3
// the other way is using the Spread Syntax
const obj4 = {...obj1.data}
obj4.value++;
console.log(`obj4.value = ${obj4.value}`);
// --> obj4.value = 4
console.log(`obj1.data.value = ${obj1.data.value}`);
// --> obj1.data.value = 3
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论