Reputation: 1427
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.
Upvotes: 2
Views: 498
Reputation: 5183
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.
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
Upvotes: 1
Reputation: 5183
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
Options API
to understand the problem.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);
#app { line-height: 2; }
[v-cloak] { display: none; }
<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/[email protected]/dist/vue.min.js"></script>
// 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
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')
<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>
Upvotes: 2
Reputation: 23490
Try to copy object by value, not reference:
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>
Upvotes: 2