为啥会写这么个星号玩意
在开发中遇到一个场景,在给一个数据编辑时需要绑定其他数据,这种在一般情况下是去由前端传一整个list过去由后端做处理(后端来个先删后插)即可,但是这边出现一个奇怪的场景,可绑定的其他数据可能达到24万条,所以就得前端来记录一下哪些数据被处理过,将被处理过的数据传过去。起初,我以为只是每一次对操作后数据做一个push,然后将这个操作后的数据传给后端即可,但是后端老哥对我又提出新的期望。什么意思呢?就是如果我先添加一个id为1的数据的绑定,再删除一条id为1的数据,这个表格不需要记录这条操作,以此类推,其实就是需要我们搞一个对一个id唯一的数据保存他的最后一次操作记录即可
原型图如下(俺自己画的,能看就行,不是搞产品的)
添加时选择另一个表的数据数据进行添加,选中后带出到编辑中,带出后可以自由编辑字段3,也可以在编辑页批量删除数据,只在点击抽屉底部保存时才与后端做交互,现在我们可以来拆解一下如何实现后端对前端的要求
实现步骤
拆解为三个需要记录的操作,分别为新增,编辑,删除,使用optionType属性记录,删除和新增都可能出现一次添加多条的场景,而编辑只会出现一次添加一条的场景
先来一个记录增删改查的操作
const RecordTableOperations = () => {
//记录列表
let recordList = [];
//记录新增数据
const addRecordList = (list) => {
recordList = [
...recordList,
...list.map((item) => {
return {
...item,
optionType: "add",
};
}),
];
};
//记录删除数据
const delRecordList = (list) => {
recordList = [
...recordList,
...list.map((item) => {
return {
...item,
optionType: "del",
};
}),
];
};
//记录编辑数据
const editRecordList = (obj) => {
recordList = [
...recordList,
{...obj, optionType: "edit",}
];
};
//获取当前记录列表数据
const getRecordList = () => {
return recordList;
};
return [getRecordList, addRecordList, delRecordList, editRecordList];
};
设想一下 场景1,如果每个操作的id不同,那么每次的增删改,都只会保存当前的记录,即上面的方法已经够用了 再看看场景2,即有在记录列表中有相同id,应当如何操作呢?
- 先删除再新增,此时保存状态应该为edit,因为可能出现字段3不相同的情况
- 先新增再删除,此时应该将此条id的数据完全从记录列表中剔除
- 先新增再编辑,此时保存状态应该为add,因为在编辑表格中的操作并未与后端做交互
- 先编辑再删除, 此时保存状态应该为del,因为在编辑表格中的操作并未与后端做交互
- i除非后端的返回的id有重复出现,否则在一次操作中最多出现两个id一样的数据保存进记录数组,而将其做数据处理后就会在前端只留下不同id的数据
所以需要添加一个处理数据的函数和改动之前的三个方法
const RecordTableOperations = () => {
//记录列表
let recordList = [];
const changeRecordList = (list) => {
//让_list中只存在id唯一的数据
let _recordList = recordList.filter(
(item) => !list.map((ele) => ele.id).includes(item.id)
);
let _list = [..._recordList, ...list];
let _list_ = _list.map((item) => {
return {
...item,
typeArr: [],
};
});
//将两个数据拼接后给typeArr加数据,typeArr长度为1或2
let _recordList_ = [...recordList, ...list];
for (let i = 0; i < _list_.length; i++) {
for (let j = 0; j < _recordList_.length; j++) {
if (_list_[i].id === _recordList_[j].id) {
_list_[i].typeArr.push(_recordList_[j].optionTYpe);
}
}
}
for (let i = 0; i < _list_.length; i++) {
if (_list_[i].typeArr.length === 1) {
_list_[i].optionTYpe = _list_[i].typeArr[0];
}
if (_list_[i].typeArr.length === 2) {
if (
_list_[i].typeArr[0] === "del" &&
_list_[i].typeArr[1] === "add"
) {
_list_[i].optionTYpe = "edit";
}
if (
_list_[i].typeArr[0] === "add" &&
_list_[i].typeArr[1] === "edit"
) {
_list_[i].optionTYpe = "add";
}
if (
_list_[i].typeArr[0] === "add" &&
_list_[i].typeArr[1] === "del"
) {
_list_[i].optionTYpe = null;
}
if (
_list_[i].typeArr[0] === "edit" &&
_list_[i].typeArr[1] === "del"
) {
_list_[i].optionTYpe = "del";
}
}
}
recordList = _list_
.map((item) => {
let obj = item;
delete obj.typeArr;
return {
...obj,
};
})
.filter((item) => item.optionTYpe);
};
//记录新增数据
const addRecordList = (list) => {
let _recordList = [
...list.map((item) => {
return {
...item,
optionTYpe: "add",
};
}),
];
changeRecordList(_recordList);
};
//记录删除数据
const delRecordList = (list) => {
let _recordList = [
...list.map((item) => {
return {
...item,
optionTYpe: "del",
};
}),
];
changeRecordList(_recordList);
};
//记录编辑数据
const editRecordList = (obj) => {
let _recordList = [{ ...obj, optionTYpe: "edit" }];
changeRecordList(_recordList);
};
//获取当前记录列表数据
const getRecordList = () => {
return recordList;
};
return [getRecordList, addRecordList, delRecordList, editRecordList];
};
执行结果
addRecordList([{ id: 1, text: "1" }]);
delRecordList([{ id: 3, text: "1" }]);
editRecordList({ id: 1, text: "2" });
console.log(getRecordList());
//getRecordList结果如下
[
{
"id": 3,
"text": "1",
"optionTYpe": "del"
},
{
"id": 1,
"text": "2",
"optionTYpe": "add"
}
]
前端操作结束
可能有观看的小伙伴会问为啥不直接传整个list而是传操作记录的数组,因为数据量大啊,产品设计不单独弄个页面去操作,得用一个保存来保存自身信息和绑定字段,所以搞了这么个星号玩意儿,喵的!!!掀桌子,不会干产品,他可以回去搬砖嘛,这不妥妥害人吗(小声抱怨“狗头”)