0

The question is simple, but yet I cannot figure this one out; I need to render a date-selection module, that displays the first_possible_date and the 6 next days, and the ability to navigate back and forth until the last_possible_date has been reached. Every date after the last_possible_date that is rendered needs to be disabled. Navigating back is not possible if it precedes the first_possible_date and navigating forth is not possible if it exceeds the last_possible_date.

The data I am working with is object that has days of the week as its children, like so:

{
  "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] }
}

This data is passed, along with the first_possible_date and last_possible_date to my component via the props. In the componentDidMount function, I set the data to the state, like so:

this.setState({
    data: this.props.data
}, () => {
    this.getFormattedDates(this.props.firstpossible);
});

In the getFormattedDates function, I set this data in a local variable, using the immutability React mentions in their tutorial application, preserving the data in this.state.data, like so:

let dates = Object.assign({}. this.state.data);

The categories variables contain some information I need to render some components (or not) in my UI. But as you can see, this array does not contain all days yet, so I need to add them. For this I have an array of days, and check if the iterated day of the week is in my data-array, like so:

// //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
        };
    }
}        

When this is done, I want to shift the array, so that the first_possible_date is the first in the array, so it's easier to (re-)render my date selection, like so:

// 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]);
    }
}

Lastly, I add some extra data, empty the categories variable if the date exceeds the last_possible_date (I disable the buttons if the categories array is empty), and return the data in a 4 / 3 object to be rendered, like so:

//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});

Navigating back and forth, I add, or remove days to the startdate as I go along, like so:

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);

It all works fine, even though the code may be messy, but there's a problem I need to fix.

You see, even though I created a variable from the data in this.state.data, it is still mutated, when I modify my local created variable let dates. What's even more weird, is that logging the this.state.data the first time results in the data already being modified. In between the creation of the let dates variable and the loop to add saturday and sunday to the array, I placed a log console.log(this.state.data); which shows me, even at the first iteration, that saturday, and sunday have been added, while the code below to add them has never been executed at that point (it is executed after the log). The resulting JSON looks like:

{
  "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 }
}

When the code is executed that modifies the categories variables if the current iterated date is beyond the last_possible_date, it properly empties the categories and disables the buttons in the UI, as expected. But, when you then navigate back again, they are still disabled, because the categories array stays empty. Logging the this.state.data again reveals that the data has changed, with empty categories arrays in some days.

So, tl;dr...

  • Creation of variable from state data, rendering state data immutable
  • Modification of variable
  • Modifications to variable also modify state data
  • (Optional) Modifications to variable are after logging, but still logs reflect changes on the first iteration.
Cerbrus
  • 70,800
  • 18
  • 132
  • 147
Magicbjørn
  • 619
  • 9
  • 23
  • So, you're saying `this.states.data`'s contents change when you change a value in your `dates` variable? – Cerbrus Aug 20 '18 at 09:27
  • 3
    The part about the logging being "weird" is normal: when you log an object, a reference to that object is kept. When you then go to expand the object and view its properties, you get a view of the current state, not the state at the time of logging. If you want a "frozen" state, consider `console.log(JSON.stringify(obj))` – Niet the Dark Absol Aug 20 '18 at 09:28
  • 1
    `let dates = Object.assign({}. this.state.data);` doesn't make anything "immutable". You need a deep copy, instead. – Cerbrus Aug 20 '18 at 09:31
  • @NiettheDarkAbsol Thanks for that piece of information. I did not know that! That explains a lot of things. – Magicbjørn Aug 20 '18 at 10:15
  • 1
    And @Cerbrus Right! That's it! I did not know that copying a variable copied only the reference (so that they are both modified when changes occur). This makes me question implementations I did in the past, but does clarify a lot! Thanks a bunch! – Magicbjørn Aug 20 '18 at 10:15

0 Answers0