javascript - 不可变对象发生了变异
问题描述
问题很简单,但我无法弄清楚这个问题;我需要渲染一个日期选择模块,显示first_possible_date
接下来的 6 天,以及来回导航直到last_possible_date
到达的能力。之后的每个日期last_possible_date
都需要被禁用。如果它在 之前,则无法向后first_possible_date
导航,如果超过 ,则无法向前导航last_possible_date
。
我正在使用的数据是具有一周中的几天作为其子对象的对象,如下所示:
{
"1": { "name": "Monday", "categories": [5] },
"1": { "name": "Tuesday", "categories": [5] },
"1": { "name": "Wednesday", "categories": [5] },
"1": { "name": "Thursday", "categories": [5] },
"1": { "name": "Friday", "categories": [5] }
}
这些数据与first_possible_date
和last_possible_date
一起通过道具传递给我的组件。在 componentDidMount 函数中,我将数据设置为状态,如下所示:
this.setState({
data: this.props.data
}, () => {
this.getFormattedDates(this.props.firstpossible);
});
在getFormattedDates
函数中,我使用 React 在他们的教程应用程序中提到的不变性将这些数据设置在一个局部变量中,将数据保存在 中this.state.data
,如下所示:
let dates = Object.assign({}. this.state.data);
类别变量包含一些我需要在我的 UI 中呈现某些组件(或不呈现)的信息。但是正如你所看到的,这个数组还没有包含所有的日子,所以我需要添加它们。为此,我有一个天数组,并检查一周中的迭代日期是否在我的数据数组中,如下所示:
// //Add saturday and sunday to the array, as well as add additional data
for (var i = 0; i < daysoftheweek.length; i++) {
let datefound = false;
let dayoftheweekindex = i * 1 + 1;
let j = (Object.keys(dates).length === 7) ? 0 : 1;
let limit = (Object.keys(dates).length === 7) ? 6 : 5;
for (j; j <= limit; j++) {
if (daysoftheweek[i].toLowerCase() === dates[j].name.toLowerCase()) {
dates[j]['dayoftheweek'] = dayoftheweekindex;
dates[j]['name'] = dates[j]['name'].toLowerCase();
datefound = true;
}
}
if (!datefound) {
let newindex = dayoftheweekindex - 1;
dayoftheweekindex = (dayoftheweekindex === 7) ? 0 : dayoftheweekindex;
dates[dayoftheweekindex] = {
name: daysoftheweek[newindex],
categories: [],
dayoftheweek: dayoftheweekindex
};
}
}
完成后,我想移动数组,以便 是数组中first_possible_date
的第一个,因此更容易(重新)呈现我的日期选择,如下所示:
// Shift the array, so the first element is the day after the first possible transport date.
let shiftedDates = [];
let firstPossible = startdate.getDay();
for (var i = 0; i < Object.keys(dates).length; i++) {
let date = dates[i];
if (date.dayoftheweek < firstPossible) {
shiftedDates.splice(shiftedDates.length, 0, dates[i]);
} else {
shiftedDates.splice(i - firstPossible, 0, dates[i]);
}
}
最后,我添加了一些额外的数据,categories
如果日期超过了,则清空变量last_possible_date
(如果类别数组为空,我将禁用按钮),并在 4 / 3 对象中返回数据以进行渲染,如下所示:
//Finally, add some more data to every shifted element, so it can be used for displaying.
for (let i in shiftedDates) {
let incrementedDate = Helper.addDaysToDate(startdate, i * 1);
shiftedDates[i]['dayofthemonth'] = incrementedDate.getDate();
shiftedDates[i]['monthIndex'] = incrementedDate.getMonth();
shiftedDates[i]['month'] = months[incrementedDate.getMonth()];
shiftedDates[i]['year'] = incrementedDate.getFullYear();
let lastPossibleDate = this.props.lastpossible;
if (shiftedDates[i].monthIndex > lastPossibleDate.getMonth() || (shiftedDates[i].monthIndex === lastPossibleDate.getMonth() && shiftedDates[i].dayofthemonth > lastPossibleDate.getDate())) {
shiftedDates[i].categories = [];
}
if (true) {}
}
let formattedDates = {
0: [
shiftedDates[0],
shiftedDates[1],
shiftedDates[2],
shiftedDates[3],
],
1: [
shiftedDates[4],
shiftedDates[5],
shiftedDates[6],
]
};
this.setState({otherdates: formattedDates});
来回导航,我在前进的过程中添加或删除天数startdate
,如下所示:
let startdate = this.state.startdate;
if (moveahead) {
let startDateBuffer = Helper.addDaysToDate(startdate, 7);
if (startDateBuffer < this.props.lastpossible) {
this.hideAll();
startdate = Helper.addDaysToDate(startdate, 7);
}
} else {
if (this.props.firstpossible < startdate) {
this.hideAll();
startdate = Helper.addDaysToDate(startdate, -7);
}
}
this.getFormattedDates(startdate);
这一切都很好,即使代码可能很乱,但我需要解决一个问题。
您会看到,即使我从 中的数据创建了一个变量this.state.data
,当我修改本地创建的变量时,它仍然会发生变异let dates
。更奇怪的是,this.state.data
第一次记录导致数据已经被修改。在创建let dates
变量和将星期六和星期日添加到数组中的循环之间,我放置了一个日志console.log(this.state.data);
,显示即使在第一次迭代中,星期六和星期日也已添加,而下面添加它们的代码有那时从未执行过(它在日志之后执行)。生成的 JSON 如下所示:
{
"0": { "name": "sunday", "categories": [0], "dayoftheweek": 7, "dayofthemonth": 9, "monthIndex": 8, "month": "september", "year": 2018 },
"1": { "name": "monday", "categories": [5], "dayoftheweek": 1, "dayofthemonth": 10, "monthIndex": 8, "month": "september", "year": 2018 },
"2": { "name": "tuesday", "categories": [5], "dayoftheweek": 2, "dayofthemonth": 4, "monthIndex": 8, "month": "september", "year": 2018 },
"3": { "name": "wednesday", "categories": [5], "dayoftheweek": 3, "dayofthemonth": 5, "monthIndex": 8, "month": "september", "year": 2018 },
"4": { "name": "thursday", "categories": [5], "dayoftheweek": 4, "dayofthemonth": 6, "monthIndex": 8, "month": "september", "year": 2018 },
"5": { "name": "friday", "categories": [5], "dayoftheweek": 5, "dayofthemonth": 7, "monthIndex": 8, "month": "september", "year": 2018 },
"6": { "name": "saturday", "categories": [0], "dayoftheweek": 6, "dayofthemonth": 8, "monthIndex": 8, "month": "september", "year": 2018 }
}
categories
如果当前迭代日期超出,则执行修改变量的代码时last_possible_date
,它会按预期正确清空类别并禁用 UI 中的按钮。但是,当您再次导航回来时,它们仍然被禁用,因为类别数组保持为空。再次记录this.state.data
显示数据已更改,categories
在某些日子有空数组。
所以,tl;博士...
- 从状态数据创建变量,使状态数据不可变
- 变量的修改
- 对变量的修改也会修改状态数据
- (可选)对变量的修改是在记录之后进行的,但日志仍然反映了第一次迭代的变化。
解决方案
推荐阅读
- c - 在 C 中读取 txt 文件时遇到问题
- google-cloud-firestore - 无法将 Cloud Firestore 导入 Stripe 客户帐户
- javascript - 无法在反应组件中查看图像
- java - 某些 ascii 字符是否占用超过 1 个字节的内存?
- r - 闪亮问题的新功能
- python - Haversine 的公式实现与 SQLAlchemy 和性能
- regex - Negative Lookahead Regex 忽略了我的句子
- discord - 如何在 Discord.js 中创建谈话命令?
- reactjs - 单元测试时修改 UI
- python - 我需要加速python中的嵌套循环,它会产生数万亿个循环