Roei Grinshpan
Roei Grinshpan

Reputation: 453

Why state update one click after with flat list

to simplify the question: I have Three states

  1. massageType - user chose type of massage.
  2. avHoursInDay - to check all the available hours in the day that clicked.
  3. avHoursByType - to manipulate the array of avHoursInDay and change the hours depend on the "massageType" that the user chose.(because the massageType have different lengths so hours that available depend on the massageType).

THE QUESTION: why my state change one click late.(example in the end)

function 1 - to handle with the hours available:

    const handleDay = day => {
    setSelectedDay(day);
    const dayMeetings = weekMeetings.filter(meet => meet.startDate.split("T")[0] === day.dateString);
    let availableHours = hours.map(e => ({ ...e }));
    for (let i = 0; i < dayMeetings.length; i++) {
        for (let j = 0; j < hours.length; j++) {
            if (moment(dayMeetings[i].startDate).format("LT") === hours[j].time) {
                availableHours[j].busy = true;
                availableHours[j + 1].busy = true;
                if (dayMeetings[i].massageType === "sweden" || dayMeetings[i].massageType==="fullbody" ) {
                    availableHours[j + 2].busy = true;
                }
                break;
            }
        }
    }

    setAvHoursInDay(availableHours);
    setAvHoursByType([]);
    if (massageType.key !== -1) massageTypeHandler(massageType);

};

function 2 - to manipulate the hours available depend on massage type:

    const massageTypeHandler = item => {
    setMassageType(item);
    let mapDateByType = avHoursInDay.map(e => ({ ...e }));
    for (let i = 0; i < avHoursInDay.length; i++) {
        if ((i === avHoursInDay.length - 3 && avHoursInDay[i].busy === false && item.key === 2) || item.key === 3) {
            mapDateByType[i].busy = true;
        }
        if (i === avHoursInDay.length - 1 || i === avHoursInDay.length - 2) {
            mapDateByType[i].busy = true;
        } else if (avHoursInDay[i].busy === false) {
            if (avHoursInDay[i + 1].busy === true) {
                mapDateByType[i].busy = true;
            } else if ((item.key === 2 || item.key === 3) && avHoursInDay[i + 2].busy === true) {
                mapDateByType[i].busy = true;
            }
        }
    }
    setAvHoursByType(mapDateByType);
};

=======================

now i have flatList that when user clicked its go to function 2:

    renderItem={({ item }) => (
                    <StyledButton
                        key={item.key}
                        onPress={() => massageTypeHandler(item)}
                        buttonStyle={
                            item.key === massageType.key
                                ? [styles.massagetypebutton, styles.selectedbutton]
                                : styles.massagetypebutton
                        }
                        text={item.massageType}
                    />
                )}
                keyExtractor={item => item.key.toString()}
            />

and calendar that go to function 1 (that invoke function 2 also):

<Calendar
            minDate={new Date()}
            markedDates={{
                [selectedDay.dateString]: {
                    selected: true,
                    disableTouchEvent: true,
                },
            }}
            theme={calendarTheme}
            onDayPress={handleDay}
            style={{ marginTop: 10 }}
        />
        {selectedDay && (
            <Text style={styles.daytitle}>יום {moment(selectedDay.dateString).format("dddd  DD/MM/YYYY")}</Text>
        )}
        <AvailableHours avHoursInDay={avHoursByType} />

the question in extend: everything worked correctly and state change to the right available places. but every render change only one click after . for exmaple:

something updated in late..

help please , thanks in advance,

image for demonstration:

(I would be very happy if you could give me a code review if you see a faster way than two such long functions)

Upvotes: 0

Views: 88

Answers (1)

Or Frenkel
Or Frenkel

Reputation: 91

lift-state-up and use useReducer in order to manipulate multiple states fields simultaneously.

function FooCalendar() {
  const [state, action] = useReducer(
      /* your initial state & implementation, move your BL logic to the reducer */
      )  
    // pass the state to your components
    const { selectedDay, avHoursByType } = state;
  return (
    <>
      <Calendar
        minDate={new Date()}
        markedDates={{
          [selectedDay.dateString]: {
            selected: true,
            disableTouchEvent: true,
          },
        }}
        theme={calendarTheme}
        onDayPress={(day) => {
            action({payload: {day}, type: 'DATE_CHANGED' })}
        }
        style={{ marginTop: 10 }}
      />
      {selectedDay && (
        <Text style={styles.daytitle}>
          יום {moment(selectedDay.dateString).format('dddd  DD/MM/YYYY')}
        </Text>
      )}
      <AvailableHours avHoursInDay={avHoursByType} onMessageTypeChanged={(item) => {
        action({payload: {item}, type: 'MESSAGE_TYPE_CHANGED' })
      }} />
    </>
  );
}

Upvotes: 1

Related Questions