Ref.value is updated in array althought it shouldn't
Vue version
3
Link to minimal reproduction
Steps to reproduce
Click on button and you will see that product updated in array by itself.
Next, comment out push function in onMounted and uncomment push with shallow copy (take it from below as playground cut off any code comments). Upon clicking button product won't update by itself anymore
What is expected?
If we are pushing value to array the data shouldn't update by itself. If we call isRef(product.value) it will return false, so.... if value is not reactive why is it updating? Is pushing shallow copy a recommended way of handling such cases? Pushing unref(product.value) still causes unwanted behaviour.
What is actually happening?
Ref shouldn't update by itself.
Pasting onMounted with comments, because Vue SFC Playground cut them off
onMounted(() => {
// if we push ref's value it will update itself upon button click
products.value.push(product.value)
// if we push ({...product.value}) product wont update by itself
// products.value.push({...product.value})
})
I'm a bit confused what you are having an issue with, exactly.
In JS, objects are passed as references. pushing an object to an array does not create a new object. So changing the object in product.value
of course will affect the object in the array - because they are the same object. That's just JS.
I think you are kind of aware of this, as you show the "solution" yourself: make a copy of the object if you don't want one to affect the other.
So: Am I missing something?
Thanks @LinusBorg for quick response. I understand passing by reference. Therefore I have updated reproduction. Using plain JS won't cause update in jsProducts array.
TLDR it won't cause template update, but array will still be updated. The lack of template update caused wrong assumptions.
import { ref, onMounted } from 'vue'
const products = ref([])
const product = ref({sku: '123abc'})
let jsProducts = []
let jsProduct = {sku: '123abc'}
const updateProduct = () => {
product.value.afterPush = true
}
const updateJsProduct = () => {
jsProduct.afterPush = true
}
onMounted(() => {
products.value.push(product.value)
jsProducts.push(jsProduct)
})
Manipulating a nonreactive array will not cause a re-render, so the ouput in the html does not change. That's also expected.
You can see that the plain array also changed when you change the reactive one - then the component updates the whole template and you see both arrays containing the new property.
Still all expected behavior. Still just passing an object reference.