javascriptvue.jsvuejs3vue-composition-apivue-reactivity

Vue 3: Remove objects (Proxies) from Array


I have a vue3 project and I use the composition API. I have a component which shows some items (called tokens in this case).

<script setup>
import { ref, onMounted, toRaw } from 'vue'
import RotaryToken from './RotaryToken.vue'

const tokens = ref([])

const addToken = () => {
  const id = new Date().valueOf()
  tokens.value.push({ id })
}

const removeToken = (id) => {
  console.log('id: ', id)
  tokens.value = tokens.value.filter((token) => {
    console.log('toRaw(token): ', toRaw(token))
    return token.id !== id
  })
  console.log('tokens.value: ', tokens.value)
}
</script>

<template>
  <div class="canvas">
    <div class="controls"><button @click="addToken">Add token</button></div>
    <div v-if="tokens.length <= 0" class="fallback-message">Place tokens here</div>
    <RotaryToken
      v-for="token in tokens"
      :key="token.id"
      @destroy="removeToken"
      :id="token.id"
    />
  </div>
</template>

The RotaryToken itself can emit a destroy event so I can remove itself from the array and therefore it should be removed. (I tried to self destroy a rotary token but no success).

Unfortunately I cannot remove a token from the reactive tokens array . The problem lies somewhere in Vues Reactivity stuff.

enter image description here

I can see that the id is the correct one but tokens.value.filter just does not work. I tried with splicing instead of filtering, added nextTick. Nothing worked.

Maybe somebody has an idea how to remove a token from the array and make it therefore rerender the template and removing destroyed tokens?


Solution

  • The problem is your filter test.

    tokens.value.filter((token) => {
        console.log('toRaw(token): ', toRaw(token))
        return token.id !== id
    })
    

    where you believe id is a number, but as your screenshot shows, it's an object called "id" but also with an id property. So your filter test is only returning tokens where token.id !== object

    Either pass the actual id property to the function, or access the property on the object which would be id.id:

    tokens.value.filter((token) => {
        console.log('toRaw(token): ', toRaw(token))
        return token.id !== id.id
    })