数组内部的引用意外行为

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

Refs inside arrays unexpected behavior

问题

I am trying to use an v-model with a custom component. More specifically I was using an v-for to generate a list of elements based on infomations in an array. In practice, the components did not behave as I expected... the problem seems to arise from how the ref(s) are treated and I can't find the reason for it nor a solution.

This is my test code, from which I expect the same result on both rows, but it doesn't:

// App.vue
<script setup>
import { ref } from 'vue'
import CustomInput from './CustomInput.vue'
  
const message = ref('hello')
const myArr = [message]
 
</script>

<template>
  <CustomInput v-model="message" /> {{ message }}
  <br/>
  <CustomInput v-model="myArr[0]" /> {{ myArr[0] }}
</template>
// CustomInput.vue
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>

<template>
  <input
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>

Playground Project

I premise that I am new to Vue, and have only read a small part of the documentation at the moment, so I apologize if there is anything I missed that would allow a simple and obvious solution to the question.

I tried wrapping the array in a ref or reactive (read around) but it doesn't seem to work.

I am sure there are solutions such as hardcoding the components to solve my original problem. But mine is mainly an educational question, so the code shown above I think extrapolates well to the problem I'm interested in. Thank you in advance for your answers.

英文:

I am trying to use an v-model with a custom component. More specifically I was using an v-for to generate a list of elements based on infomations in an array. In practice, the components did not behave as I expected... the problem seems to arise from how the ref(s) are treated and I can't find the reason for it nor a solution.

This is my test code, from which I expect the same result on both rows, but it doesn't:

// App.vue
<script setup>
import { ref } from 'vue'
import CustomInput from './CustomInput.vue'
  
const message = ref('hello')
const myArr = [message]
 
</script>

<template>
  <CustomInput v-model="message" /> {{ message }}
  <br/>
  <CustomInput v-model="myArr[0]" /> {{ myArr[0] }}
</template>
// CustomInput.vue
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>

<template>
  <input
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>

Playground Project

I premise that I am new to Vue, and have only read a small part of the documentation at the moment, so I apologize if there is anything I missed that would allow a simple and obvious solution to the question.

I tried wrapping the array in a ref or reactive (read around) but it doesn't seem to work.

I am sure there are solutions such as hardcoding the components to solve my original problem. But mine is mainly an educational question, so the code shown above I think extrapolates well to the problem I'm interested in. Thank you in advance for your answers.

答案1

得分: 1

通常,在您的<template>代码中使用的引用会自动“解封装”,因此v-model="message"实际上变成了v-model="message.value",其中.value是内部值'hello'

使用v-model="myArr[0]"实际上是通过分配一个数组索引来隐藏它是引用的事实。在这种情况下,Vue 不会聪明到知道它是引用,这导致整个引用代理对象被分配给 v-model。这就是为什么您在输入框中看到[object Object]而不是内部值的原因。简单的修复方法是通过指定.value来自行解封装值。

<CustomInput v-model="myArr[0].value" /> {{ myArr[0].value }}

[更新的 Playground](https://play.vuejs.org/#eNp9UEtrg0AQ/ivDEtBAqj2LCQ2lh9566sX1YOOYCu6DfQhF/O+dVRETQm678z1nBnbWOuk9sozl9mJa7cCi8/rEZSu0Mg4GMNjACI1RAiKiRiv07q1T4lNq7xY4STez4EtkAC4vSloHAq2trgjHYBlHv9h1Ktqv6N/ZGMKKhVaSlMs8nWtRIfo4FLqrHNIPIN/m9y9C1dgdOVvknEF6gmFYU8dxEv2Y9Kk6tChey6SvOr8xuRlPXnm6tmEHdrf3g3vW2LQSv4zSNi6iKe87mEUlnWAGP0TrAuh1TbbZHefZKdoQHF4A2VQxrLLKOZuht4lG0A4pKX6Qc4Ad9ihd4ipzRVolTPezPtxtu/T4D5IwykU=


<details>
<summary>英文:</summary>

Normally a ref used in your `&lt;template&gt;` code is automatically &quot;unwrapped&quot;, so `v-model=&quot;message&quot;` actually becomes `v-model=&quot;message.value&quot;`, where `.value` is the inner value `&#39;hello&#39;`. 

With `v-model=&quot;myArr[0]&quot;` you&#39;re basically hiding the fact that it&#39;s a ref by assigning an array index. Vue isn&#39;t _that_ smart to know it&#39;s a ref in this case, which results in the entire ref proxy object being assigned to the v-model. This is why you see `[object Object]` in the input instead of the inner value.  The simple fix is to unwrap the value yourself by specifying `.value`

```html
&lt;CustomInput v-model=&quot;myArr[0].value&quot; /&gt; {{ myArr[0].value }}

updated Playground

答案2

得分: 1

这不是Vue中的响应式变量,因此对于这种变量,将不可用于响应式渲染或更新。此外,您必须使用 message.value 来引用脚本中 message ref 的值。

const myArr = [message]

如果您想使用多个输入并跟踪它们的输入,以下是一种解决方法:

&lt;script setup&gt;
import { ref } from &#39;vue&#39;
import CustomInput from &#39;./CustomInput.vue&#39;

const myArr = ref([
  {id: 1, message: null, holder: &quot;Holder1&quot;},
  {id: 2, message: null, holder: &quot;Holder2&quot;}
])
&lt;/script&gt;

&lt;template&gt;
  &lt;CustomInput v-model=&quot;message&quot; /&gt; {{ message }}
  &lt;br/&gt;
  &lt;template v-for=&quot;item in myArr&quot; :key=&quot;item.id&quot;&gt;
    &lt;CustomInput v-model=&quot;item.message&quot; :placeholder=&quot;item.holder&quot; /&gt;{{item.message || &#39;None&#39;}}&lt;br/&gt;
  &lt;/template&gt;
&lt;/template&gt;

示例位于 [Vue Sfc Playground](https://play.vuejs.org/#eNqFUsFqwkAQ/ZVhKUQhTdBjUKmUQnspPfXierBm1KWb3WWzESTm3zubjTGIbW+Zee/Nm3nZmi2NSY4VsozNyq0VxkGJrjILrkRhtHVQg8UdNLCzuoCIqFEPPVel08WbMpXr4CQd9PxcIgNwtdWqdFBgWW72CHM/chQdUEodjXv0tLS2w1ZeVos8g0l8kWWgKiljOGiZo82As9f2a8JZE/f86b/8KfG5Wg99lXYHtMF+1cmT40ZWuA4sLTGRej8acmkAXTZLQ2wUGBUOCyM3DqkCmA3zOT4WOkc556ybzxmkC6jrPpWGtiLRl02D+jKLpDttSSioA0KFoEiefeOpayci56yV/Wrb0q7eGc3eYsjmgoaqXayuh3w4nyF61wqjprkumA6uHRQsZjeP4M7jynEnFH5YbcrRKmp3/PR5R/6/BPClEM6DlclpbHbD+St34Y1DGFn7F33qvZyzAD21NIIekJxGd3xieMAjKpe4jd0jneK746D3GQyPbn4A010mtA==


<details>
<summary>英文:</summary>

This is not a reactive variable in Vue, so reactive rendering|update will not be available for such variable. Plus you have to use `message.value` to reference the value of `message` ref inside the script.
```js
const myArr = [message]

If you want to use multiple inputs and track their inputs here is one workaround:

&lt;script setup&gt;
import { ref } from &#39;vue&#39;
import CustomInput from &#39;./CustomInput.vue&#39;
  
const myArr = ref([
  {id: 1, message: null, holder: &quot;Holder1&quot;},
  {id: 2, message: null, holder: &quot;Holder2&quot;}
])
&lt;/script&gt;

&lt;template&gt;
  &lt;CustomInput v-model=&quot;message&quot; /&gt; {{ message }}
  &lt;br/&gt;
  &lt;template v-for=&quot;item in myArr&quot; :key=&quot;item.id&quot;&gt;
    &lt;CustomInput v-model=&quot;item.message&quot; :placeholder=&quot;item.holder&quot; /&gt;{{item.message || &#39;None&#39;}}&lt;br/&gt;
  &lt;/template&gt;
&lt;/template&gt;

Example at Vue Sfc Playground

huangapple
  • 本文由 发表于 2023年6月13日 09:41:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76461217.html
匿名

发表评论

匿名网友

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

确定