不可变对象被突变

时间:2018-08-20 09:22:32

标签: javascript reactjs immutability

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

category变量包含一些我需要在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变量(如果categorys数组为空,则禁用按钮),并以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; dr ...

  • 根据状态数据创建变量,使状态数据不可变
  • 修改变量
  • 对变量的修改也会修改状态数据
  • (可选)对变量的修改是在记录后进行的,但日志仍会反映出第一次迭代的变化。

0 个答案:

没有答案