Mapping array objects and updating state variable. data is lost

Viewed 187

I want an array of days to update to same start time and end time and update it a state variable. When i am mapping the array of days to the update state variable form. When checking the console logs. either only starttime updates or endtime or only 1 day is updated to the state variable

const daystime={
    sunday: {
      start: "3000",
      end: "3000",
    },
    monday: {
      start: "3000",
      end: "3000",
    },
    tuesday: {
      start: "3000",
      end: "3000",
    },
    wednesday: {
      start: "3000",
      end: "3000",
    },
    thursday: {
      start: "3000",
      end: "3000",
    },
    friday: {
      start: "3000",
      end: "3000",
    },
    saturday: {
      start: "3000",
      end: "3000",
    },
  }
  const [form, setForm] = React.useState(daystime);
  const [singleStartTime, setSingleStartTime] = React.useState(new Date());
  const [singleEndTime, setSingleEndTime] = React.useState(new Date());
useEffect(() => {
    if(value==='Same Timing'){
    let starttime='3000'
    let endtime='3000'
    if (singleStartTime._d) {
      if(singleStartTime._d.getMinutes().toString().length<2)
      starttime = singleStartTime._d.getHours().toString() +'0'+singleStartTime._d.getMinutes().toString();
      else
      starttime =singleStartTime._d.getHours().toString() +singleStartTime._d.getMinutes().toString();
      
      days.map((day) => {
        pass(day.title, "start", starttime);
        return "";
      });
    }
    if (singleEndTime._d) {
      if(singleEndTime._d.getMinutes().toString().length<2)
      endtime = singleEndTime._d.getHours().toString() +'0'+singleEndTime._d.getMinutes().toString();
      else
      endtime =singleEndTime._d.getHours().toString() +singleEndTime._d.getMinutes().toString();
      days.map((day) => {
        pass(day.title, "end", endtime);
        return "";
      });
    }}
  }, [singleStartTime, singleEndTime, days]);

  const pass = (day, side, time) => {
    setForm({
      ...form,
      [`${day}`]: { ...form[`${day}`], [`${side}`]: time },
    });
  };
1 Answers
  • Problem

Setting State works asyncronously.

So if you do : setCounter(counter + 1); setCounter(counter + 1); it doesn't add 2 to counter (instead it adds only 1 to it), because you should let the state variable to update, before applying the new State to it. (see it live)

In your case, you are changing startDate and endDate in your state variable for 7 days (28 state updates), without letting the form state variable to update :

const [form, setForm] = useState({'sunday': {start: 1, end: 2},
                                    'monday': {start: 1, end: 2}})
setForm([...form, {sunday: {...form.sunday, start: 100}}]);
setForm([...form, {sunday: {...form.sunday, end: 200}}]);
// After update, the form will be: {'sunday': {start: 1, end: 200}, ...}
// !!! PROBELM !!! You shouldn't use multiple setForms right after each others !!!
  • Solution:

Instead of setting the state multiple times without letting the new state to apply, you should first calculate your new state, and then apply it.

(Like let v = 1 + 1; setCounter(counter => counter + v);)

(Solution2: You can also use callbacks like setCounter(counter => counter + 1); setCounter(counter => counter + 1);, so it'll use the prev state.)

Run It On Codesandbox

useEffect(() => {
 // clone state here
  let newForm = JSON.parse(JSON.stringify(form))
  ...
    if (singleStartTime._d) {
    ...      
      days.forEach(day => {
        newForm = {
          ...newForm,
          [day.title]: { ...newForm[day.title], start: starttime }
        };
      });
    }
   // Do the same for EndTime
   // Apply the new state
   setForm(newForm)
...
}

Run It On Codesandbox

Related