In my app I want to occasionally replace my ref<number[]> array with a new array, which is not a ref. The way I did it, was
list2.value = listNoRef;
console.log(list2.value);
The array list2
is used inisde my template to render a list.
My logging is schowing, that the Proxy
has a modified Target
with the right values, but my browser is not rerendering. If there is another event happening, which forces a rerender, the list is shown with the added values.
Example
info:
addAnswer1()
-> worksaddAnswer2()
-> ❗problem❗addAnswer2Clear()
-> works
<script setup lang="ts">
import { ref } from 'vue';
const list1 = ref<number[]>([]);
const list2 = ref<number[]>([]);
let idx1 = 0;
let idx2 = 0;
const listNoRef: number[] = []
function addAnswer1() {
list1.value.push(idx1);
console.log(list1.value);
idx1 ;
}
function addAnswer2() {
listNoRef.push(idx2);
list2.value = listNoRef;
console.log(list2.value);
idx2 ;
}
function addAnswer2Clear() {
listNoRef.push(idx2);
list2.value = [];
list2.value = listNoRef;
console.log(list2.value);
idx2 ;
}
</script>
<template>
<h1>My Test</h1>
<h2>addAnswer1</h2>
<button @click="addAnswer1()">addAnswer1</button>
<ul>
<li v-for="item in list1" :key="item">idx:{{ item }}</li>
</ul>
<div>{{ list1.length }}</div>
<h2>addAnswer2</h2>
<button @click="addAnswer2()">addAnswer2</button>
<button @click="addAnswer2Clear()">addAnswer2Clear</button>
<ul>
<li v-for="item in list2" :key="item">idx:{{ item }}</li>
</ul>
<div>{{ list2.length }}</div>
</template>
note: This is a stripped down example. I used a similar implementation to reset a list inside a callback, after an async api call finished.
Additions
I looked for vue ref array replace rerender ...
related problems, but haven't found my specific case.
My current workaround is to clear the list of the .value
and reassign it afterwards
function addAnswer2Clear() {
listNoRef.push(idx2);
list2.value = [];
list2.value = listNoRef;
console.log(list2.value);
idx2 ;
}
What is the reason behind this problem and is there a better way to solve this?
CodePudding user response:
You can try with list2.value = [...listNoRef]
(copy by value not by reference) :
const { ref } = Vue
const app = Vue.createApp({
setup() {
const list1 = ref([]);
const list2 = ref([]);
let idx1 = 0;
let idx2 = 0;
const listNoRef = []
function addAnswer1() {
list1.value.push(idx1);
console.log(list1.value);
idx1 ;
}
function addAnswer2() {
listNoRef.push(idx2);
list2.value = [...listNoRef];
console.log(list2.value);
idx2 ;
}
return {
list1, list2, addAnswer1, addAnswer2
};
},
})
app.mount('#demo')
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<div id="demo">
<h1>My Test</h1>
<h2>addAnswer1</h2>
<button @click="addAnswer1()">addAnswer1</button>
<ul>
<li v-for="item in list1" :key="item">idx:{{ item }}</li>
</ul>
<div>{{ list1.length }}</div>
<h2>addAnswer2</h2>
<button @click="addAnswer2()">addAnswer2</button>
<ul>
<li v-for="item in list2" :key="item">idx:{{ item }}</li>
</ul>
<div>{{ list2.length }}</div>
</div>