Vue3对“外部”数组的响应性

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

Vue3 reactivity of an "external" array

问题

在将现有的Vue2应用程序迁移到Vue3时,我面临了一个令人惊讶的问题。

如何让Vue3监视一个“外部”数组的变化?

在Vue2中,这个方法运行得非常完美,但在Vue3中停止工作:

<ul id="list">
    <li v-for="t in dataArray">{{t}}</li>
</ul>

<script>
    var numbers = [1,2,3]; //这是我的外部数组

    var app = Vue.createApp({
        data() { return { dataArray : numbers } } //将Vue绑定到我的外部数组
    }).mount("#list");

    numbers.push(4); //UI没有更新,在Vue2中可以正常工作

</script>

我知道我可以调用 app.dataArray.push 或者调用 $forceUpdate 等方法,但是否有一种方法可以让Vue简单地监视现有数组的变化?

我猜更广泛的问题是:如何将Vue3绑定到任意的纯JS对象?这个对象可能太复杂以至于无法重写,或者可能来自我无法控制的外部API。这在Vue2或Angular中都很容易实现(与任何纯对象的双向绑定,无论它是否是实例/组件的一部分)。

P.S. 这似乎是Vue3中的一个巨大的变化,但在任何地方都没有提到。

更新:

根据@Dimava的回答,修复上面的代码看起来最不痛苦的方法如下:

var numbers = [1,2,3]; //这是我的外部数组
numbers = Vue.shallowReactive(numbers); //将其转换为响应式代理
英文:

While porting an existing app from Vue2 to Vue3 I faced a surprising problem.

How can I make Vue3 watch an "external" array for changes?

This worked perfectly fine in Vue2, but stopped working in Vue3:

&lt;ul id=&quot;list&quot;&gt;
	&lt;li v-for=&quot;t in dataArray&quot;&gt; {{t}} &lt;/li&gt;
&lt;/ul&gt;

&lt;script&gt;
	var numbers = [1,2,3]; //this is my external array

	var app = Vue.createApp({
		data() { return { dataArray : numbers } } //bind Vue to my external array
	}).mount(&quot;#list&quot;);

	numbers.push(4); //UI not updating, but worked fine in Vue2

&lt;/script&gt;

I know I can call app.dataArray.push instead, or call $forceUpdate, etc. but is there a way to force Vue to simply monitor an existing array?

I guess the broader question is: how to bind Vue3 to an arbitrary plain-JS object? The object can be too complex to rewrite or can come from an external API that I don't control. This is trivial in Vue2 or Angular (two-way binding with any plain object, whether or not it's part of the instance/component)

P.S. This looks like a huge breaking change in Vue3 that is not mentioned anywhere at all.

UPDATE:

According to a @Dimava's answer it looks looks like the least painful way of fixing the above code is this:

var numbers = [1,2,3]; //this is my external array
numbers = Vue.shallowReactive(numbers); //convert to a reactive proxy

答案1

得分: 5

你需要将数组变为Reactive ¹

import { reactive, ref } from 'vue'
const numbers = [1, 2, 3];
const reactiveNumbers = reactive(numbers)
reactiveNumbers.push(4)

// 或者,如果你需要重新分配整个数组
const numbersRef = ref(numbers)
numbersRef.value.push(4)
numbersRef.value = [3, 2, 1]

// 或者,如果你采用旧的方式
const data = reactive({
  numbers: [1, 2, 3]
})
data.numbers.push(4)
data.numbers = [3, 2, 1]

¹(如果包含许多不应该因性能原因而变为响应式的大对象,则使用 ShallowReactive

英文:

You need to make your array Reactive ¹

import { reactive, ref } from &#39;vue&#39;   
const numbers = [1,2,3];
const reactiveNumbers = reactive(numbers)
reactiveNumbers.push(4)

// or, if you will need to reassign the whole array
const numbersRef = ref(numbers)
numbersRef.value.push(4)
numbersRef.value = [3, 2, 1]

// or, in the old style, if you are old
const data = reactive({
  numbers: [1, 2, 3]
})
data.numbers.push(4)
data.numbers = [3, 2, 1]

¹ (or ShallowReactive if it contains a lot of big objects that shouldn't be reactive for performance reasons)

huangapple
  • 本文由 发表于 2023年6月19日 05:58:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76502682.html
匿名

发表评论

匿名网友

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

确定