英文:
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:
<ul id="list">
<li v-for="t in dataArray"> {{t}} </li>
</ul>
<script>
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("#list");
numbers.push(4); //UI not updating, but worked fine in Vue2
</script>
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 'vue'
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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论