首页 > 解决方案 > 不可变对象发生了变异

问题描述

问题很简单,但我无法弄清楚这个问题;我需要渲染一个日期选择模块,显示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_datelast_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;博士...

标签: javascriptreactjsimmutability

解决方案


推荐阅读