Home > OS >  vue3, composition api, ref array, replacement is not forcing rererendering
vue3, composition api, ref array, replacement is not forcing rererendering

Time:11-12

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() -> works
  • addAnswer2() -> ❗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>

  • Related