为什么响应变量在未分配给 v-model 时发生变化

huangapple go评论64阅读模式
英文:

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。

奇怪的是,当我开始在文本字段中输入时,它会更改transactionpbl对象中的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 = () =&gt; {
    axios({
        method: &quot;get&quot;,
        url: &quot;pay-by-link&quot;,
        params: {
            merchantUuid: import.meta.env.VITE_MERCHANT_UUID,
            uuid: route.params.uuid,
        },
    })
        .then((res) =&gt; {
            transaction.value = res.data;
            pbl = res.data;            
        })
        .catch((e) =&gt; {
            console.log(e);
        });
}

getPayByLinkTransaction();

Then I have the following textfield:

&lt;v-text-field v-model=&quot;transaction.reference&quot; variant=&quot;solo&quot; class=&quot;mb-1&quot;
:rules=&quot;config?.fields?.reference?.required ? required : []&quot;&gt;&lt;/v-text-field&gt;

PBL - {{ pbl.reference }} &lt;br&gt;
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.

为什么响应变量在未分配给 v-model 时发生变化

答案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中的相同对象分配给transactionpbl
因为它是相同的对象,所以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: &#39;#app&#39;,
  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 -->

&lt;div id=&quot;app&quot;&gt;
&lt;button type=&quot;button&quot; @click=&quot;replaceObj()&quot;&gt;Replace My Object&lt;/button&gt;&lt;hr/&gt;
My Object Id: {{myObj.id}}&lt;br/&gt;
Counter: {{myObj.counter}}
&lt;button type=&quot;button&quot; @click=&quot;plus()&quot;&gt;+1&lt;/button&gt;&lt;br/&gt;
&lt;hr/&gt;
My Object Copy Id: {{myObjCopy.id}}&lt;br/&gt;
Counter: {{myObjCopy.counter}}
&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;https://unpkg.com/vue@2.7.14/dist/vue.min.js&quot;&gt;&lt;/script&gt;

<!-- 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 = () =&gt; {
      myObj.value.counter++; 
    }    
    const replaceObj = () =&gt; {
      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(&#39;#app&#39;)

<!-- language: lang-html -->

&lt;div id=&quot;app&quot;&gt;
&lt;button type=&quot;button&quot; @click=&quot;replaceObj()&quot;&gt;Replace My Object&lt;/button&gt;&lt;br/&gt;&lt;br/&gt;
My Object Id: {{myObj.id}}&lt;br/&gt;
Counter: {{myObj.counter}}
&lt;button type=&quot;button&quot; @click=&quot;plus()&quot;&gt;+1&lt;/button&gt;&lt;br/&gt;
&lt;hr/&gt;
My Object Copy Id: {{myObjCopy.id}}&lt;br/&gt;
Counter: {{myObjCopy.counter}}
&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;https://unpkg.com/vue@3/dist/vue.global.prod.js&quot;&gt;&lt;/script&gt;

<!-- 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: &#39;reference&#39;}
    data1.value = byReference
    data2 = byReference
    
    const byValue = {ref: &#39;value&#39;}
    const data3 = ref({})
    let data4 = reactive({})
    data3.value = byValue
    data4 = {...byValue}
    
    return {
      data1, data2, data3, data4
    };
  },
})
app.mount(&#39;#demo&#39;)

<!-- language: lang-html -->

&lt;script src=&quot;https://unpkg.com/vue@3/dist/vue.global.prod.js&quot;&gt;&lt;/script&gt;
&lt;div id=&quot;demo&quot;&gt;
  &lt;input v-model=&quot;data1.ref&quot; /&gt;
  {{data1.ref}}
  {{data2.ref}}
  &lt;input v-model=&quot;data3.ref&quot; /&gt;
  {{data3.ref}}
  {{data4.ref}}
&lt;/div&gt;

<!-- 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 ); // --&gt; 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}`);
// --&gt; obj1.data.value = 1

const obj2 = obj1.data;
obj2.value++;
console.log(`obj1.data.value = ${obj1.data.value}`);
// --&gt; obj1.data.value = 2

console.log(`obj1.data == obj2 : ${obj1.data == obj2}`);
// --&gt; true 

// even the JavaScript object destructuring assignment 
// doesn&#39;t break the connection to original data Object
const { data } = obj1;
data.value++;
console.log(`obj1.data.value = ${obj1.data.value}`);
// --&gt; obj1.data.value = 3

// this works, since &#39;value&#39; is passed by value, not reference
const obj3 = { value: obj1.data.value }
obj3.value++;
console.log(`obj3.value = ${obj3.value}`);
// --&gt; obj3.value = 4
console.log(`obj1.data.value = ${obj1.data.value}`);
// --&gt; obj1.data.value = 3

// the other way is using the Spread Syntax
const obj4 = {...obj1.data}
obj4.value++;
console.log(`obj4.value = ${obj4.value}`);
// --&gt; obj4.value = 4
console.log(`obj1.data.value = ${obj1.data.value}`);
// --&gt; obj1.data.value = 3

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年2月14日 01:34:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/75439346.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定