jcmujica
jcmujica

Reputation: 91

Updating state again after it has already been updated

I am building a calendar React.js app.

When I click on a cell in my calendar, it creates a new event, it is added to an EventList state.

EventList = [{},{},{},{}];

When I create a new event I need to update the width property in all other events in this array to make them visible.

  const createEvent = (e) => {
    let startTime = e.target.id;
    let endTime = day[day.indexOf(e.target.id) + 1];
    let newEvent = {
      id: uuid(),
      startTime,
      endTime,
      height: columnHeight,
      width: 90,
      seq: [startTime, endTime],
    };
    let updEvents = [...events, newEvent];
    setevents(updEvents);
    console.log(newEvent.seq);
    getCollisions()
  };
  const getCollisions = () => {
    let zIndex = 0;
    setzIndexState(0);
    for (let slot of day) {
      let eventsInThisSlot = events.filter((event) => (
        event.startTime === slot
      ));
      if (eventsInThisSlot.length > 0) {
        console.log('eventsInThisSlot', eventsInThisSlot)
        let sorted = sortArrays(eventsInThisSlot);
        let width = 100;
        let updEvents = [...events];
        let index = -1;
        for (let event of sorted) {
          width = findParentWidth(slot);
          index = updEvents.findIndex(obj => obj.id === event.id);
          updEvents[index].width = width * (1 - (sorted.indexOf(event) / sorted.length));
          updEvents[index].zIndex = zIndex;
          console.log('zindex', updEvents[index].zIndex)
          zIndex++;
          setevents([
            ...updEvents
          ]);
        };
      }
    }
    setzIndexState(zIndex);
  }

My getCollisions function needs to go through the entire list and update the widths after calculating the correct proportions.

The first event gets added ok, however when I try to add a second event, it doesn't get added.

I think the second function has to be run after I've made sure that the element has been added to the state.

I tried tho think of a solution using useEffect but of course this creates an infinite loop.

Upvotes: 0

Views: 40

Answers (1)

Wiyanto Tan
Wiyanto Tan

Reputation: 78

const createEvent = (e) => {
    let startTime = e.target.id;
    let endTime = day[day.indexOf(e.target.id) + 1];
    let newEvent = {
      id: uuid(),
      startTime,
      endTime,
      height: columnHeight,
      width: 90,
      seq: [startTime, endTime],
    };
    let updEvents = [...events, newEvent];
    // setevents(updEvents); // <-- update update your state after getColiisions done
    console.log(newEvent.seq);
    getCollisions(updEvents); // <-- pass all the new events
  };

And then

const getCollisions = (allEvents) => { // <--- get the events
    let zIndex = 0;
    setzIndexState(0);
    let updEvents = [...events]; // <--- create new updEvents
    for (let slot of day) {
      let eventsInThisSlot = allEvents.filter((event) => ( // <-- use the events arguments.
        event.startTime === slot
      ));
      if (eventsInThisSlot.length > 0) {
        console.log('eventsInThisSlot', eventsInThisSlot)
        let sorted = sortArrays(eventsInThisSlot);
        let width = 100;
        let index = -1;
        for (let event of sorted) {
          width = findParentWidth(slot);
          index = updEvents.findIndex(obj => obj.id === event.id);
          updEvents[index].width = width * (1 - (sorted.indexOf(event) / sorted.length));
          updEvents[index].zIndex = zIndex;
          console.log('zindex', updEvents[index].zIndex)
          zIndex++;
        };
      }
    }

    setevents([ // <--- set the event at once
        ...updEvents
    ]);
    setzIndexState(zIndex);
  }

if you need to use useEffect hook, I think better to set the event state as:

const [event, setevent] = useState({
    data: [],
    version: 0
});

and then set the version increment by 1 in the createEvent method as like this

const createEvent = (e) => {
    ...
    let updEvents = [...events, newEvent];
    setevents({
        data: updEvents,
        version: events.version+1 //<--- increment version just in createEvent method
    });
    console.log(newEvent.seq);
    getCollisions()
  };

and then hook the useEffect like this...

useEffect(() => {
    ...
}, [events.version]);

Upvotes: 1

Related Questions