Vue 3: 从数组中删除对象(代理)

Vue 3: Remove objects (Proxies) from Array

提问人:Merc 提问时间:11/17/2023 更新时间:11/20/2023 访问量:34

问:

我有一个 vue3 项目,我使用组合 API。 我有一个组件,它显示一些项目(在本例中称为令牌)。

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

RotaryToken 本身可以发出 destroy 事件,因此我可以将自身从数组中删除,因此应该将其删除。(我试图自毁一个旋转令牌,但没有成功)。

不幸的是,我无法从反应式数组中删除令牌。问题出在 Vues Reactivity 的某个地方。tokens

enter image description here

我可以看到 id 是正确的,但就是不起作用。 我尝试过拼接而不是过滤,添加了.没有任何效果。tokens.value.filternextTick

也许有人知道如何从数组中删除令牌并使其重新呈现模板并删除已销毁的令牌?

javascript vue.js vuejs3 vue-composition-api vue-reactivity

评论

0赞 Estus Flask 11/17/2023
请为您的问题提供 stackoverflow.com/help/mcve。一般来说没有这样的问题,它特定于您的情况。大多数时候,强调“代理”是没有意义的,它只是 vue 实现响应式的一种方式,而且大多数时候它对用户是透明的。如果在过滤器中按对象引用而不是 id 进行比较,则会出现问题,但事实并非如此。
0赞 cantdocpp 11/17/2023
您是否尝试过记录您的代币价值?console.log(tokens.value[0].id)
0赞 Merc 11/17/2023
@EstusFlask你是对的。我认为这与反应性有关,更像是一个普遍的问题。不过,这是一个愚蠢的错误。我道歉。

答:

1赞 yoduh 11/17/2023 #1

问题出在您的过滤器测试上。

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

你认为的地方是一个数字,但正如你的屏幕截图所示,它是一个名为“id”的对象,但也有一个属性。因此,筛选器测试仅返回以下标记ididtoken.id !== object

要么将实际属性传递给函数,要么访问对象上的属性,即:idid.id

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

评论

0赞 Merc 11/17/2023
天哪,真是个愚蠢的错误!多谢!
0赞 Laurent Schoelens 11/20/2023 #2

我建议您更改删除实现以利用数组中的 vuejs 反应性

const removeToken = (id) => {
  console.log('id: ', id)
  // search index of the token to remove by its id
  const index = tokens.value.findIndex(token => token.id === id)
  if (index >= 0) {
    // index >= 0 -> index as been found in array -> use splice method to remove item in array
    tokens.value.splice(index, 1)
  }
  console.log('tokens.value: ', tokens.value)
}

如果此代码在数组中是唯一的,则此代码应该有效。idtokens

如果不是这种情况,您可以将调用包装在这样的循环中:splicewhile

const removeToken = (id) => {
  console.log('id: ', id)
  // search index of the token to remove by its id
  let index = tokens.value.findIndex(token => token.id === id)
  while (index >= 0) {
    // index >= 0 -> index as been found in array -> use splice method to remove item in array
    tokens.value.splice(index, 1)
    // and update the index var to search for a new token in the tokens array
    index = tokens.value.findIndex(token => token.id === id)
  }
  console.log('tokens.value: ', tokens.value)
}

评论

0赞 Merc 11/21/2023
实际上上面的代码有效,我已经接受了答案。无论如何,谢谢!
0赞 Laurent Schoelens 11/21/2023
没问题:)我没有抓住 is 一个对象,因为 is 在它本身上被调用。使用 vuejs 原生响应式函数可以提供更高的性能,因为你不需要每次都重新创建数组。id@destroy="removeToken"token