Search code examples
vue.jsvuejs3

Vue3 reactivity of an "external" array


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]; //my external array that came from API
numbers = Vue.shallowReactive(numbers); //convert to a reactive proxy

Solution

  • 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)