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;
});
},
我的 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;
});
},