Table 排序时 Vue v-for 循环中的重复键

Duplicate Keys in Vue v-for Loop When Table is Sorted

我的 Vue 应用程序使用 vuefire 从 Firestore 导入数据。

我从 'lines' 集合中导入数据,如下所示:

firestore() {
  return {
    lines: db.collection("lines")
  }
}

每条记录都有一个 Firestore 生成的 ID,然后我在 v-for 循环中使用一个键,例如:

<thead>
  <tr>
    <th>Code</th>
    <th @click="sort_string(lines,'name')"> Name</th>
    <th>Quantity</th>
  </tr>
</thead>
<tbody v-for="line in lines" :key="line.id">
  <tr>
    <td>{{line.code}}</td>
    <td>{{line.name}}</td>
    <td>{{line.quantity}}</td>
    <button @click="pick_one(line)">+1</button>
    ...

有一个方法pick_one直接更改 Firestore 上的数量:

pick_one(line) {

  const new_quantity = line.quantity + 1;      
  db
    .collection("lines")
    .doc(line.id)
    .update({ quantity: new_quantity });
}

所有这些工作正常直到sort()底层数组('lines').

如果我对 table 进行排序,然后调用函数 pick_one,我会收到重复键错误:

[Vue warn]: Duplicate keys detected: 'RaTIINFWTQxHQPyRmfsQ'. This may cause an update error.

我只能假设这与 Vuefire 处理 update() 调用的方式有关,因为对数组进行排序的行为不会导致此问题,只会更新数组中的一行已排序。

我的排序函数(vue 方法)如下所示:

sort_string(table, column) {
  console.log("sorting")
  this.sort_toggle = -this.sort_toggle;

  return table.sort((a, b) => {
    if (
      a[column].toString().toUpperCase() <
      b[column].toString().toUpperCase()
    ) {
      return -this.sort_toggle;
    }
    if (
      a[column].toString().toUpperCase() >
      b[column].toString().toUpperCase()
    ) {
      return this.sort_toggle;
    }
    return 0;
  });
},

有没有办法避免这种行为?

Phil 的评论提供了此行为的线索 - 因为 sort() 函数正在处理基础数据而不是副本。

我已经修改了我的模板,以便 v-for 现在循环遍历一个计算数组,该数组可以使用(稍微修改过的)函数进行排序。

排序函数现在使用 slice() 创建底层数组的副本:

computed: {
  sorted_lines() {
    return sort_string(lines, this.sort_column) // name of the column/filed to sort by
  }

sort_string 函数现在看起来像这样(加上 slice()

sort_string(table, column) {
  console.log("sorting")
  //this.sort_toggle = -this.sort_toggle; // moved elsewhere

  return table.slice().sort((a, b) => { // slice() then sort()
  if (
    a[column].toString().toUpperCase() <
    b[column].toString().toUpperCase()
  ) {
    return -this.sort_toggle;
  }
  if (
    a[column].toString().toUpperCase() >
    b[column].toString().toUpperCase()
  ) {
    return this.sort_toggle;
  }
  return 0;
});
},