0

I know that there are few posts with similar questions, but I couldn't understand how to fix the problem from them, and I'm not sure if problem is with the state.

I have a drop menu and depending on the clicked day from the drop menu I'm rendering events for that day. I'm calling a function inside useEffect which returns a boolean array and sets it to state, then I map through that state, and depending on true/false I'm rendering component or empty space. That looks like this:

At load, events state has 2 items, but EventEmptyCells is empty. After I click on any other day in the drop menu emptyEventCells state gets a value which it should get at load. And for each next click it gets the previous value.

import React, { useEffect, useState } from 'react'
import { Box, Flex } from '@chakra-ui/react'
import EventCell from 'components/schedule/events/EventCell'
import { Event } from 'components/schedule/events/EventFlex'
import { generateEmptyEventCells, calculateEventLength } from 'components/schedule/events/generateEmptyEventCells'
import { eventHours } from 'components/schedule/scheduleData'
import { scheduleData } from 'components/schedule/scheduleData'
interface Props {
    clickedDay: number
}

const MobileEventsFlex = ({ clickedDay }: Props) => {

    const [emptyEventCells, setEmptyEventCells] = useState<boolean[]>([])
    const [events, setEvents] = useState<Event[]>([])
    let counter = 0;

    useEffect(() => {
        setEvents(scheduleData[clickedDay].events)

        setEmptyEventCells(generateEmptyEventCells(events, eventHours))
    }, [clickedDay])


    return (
        <Flex flexDirection='column' w='277px' h='700px' ml='2'>
            {emptyEventCells.map((isEmpty: boolean, index) => (
                <React.Fragment key={`mobileflex${index}`}>
                    {isEmpty ? (
                        <Box h="60px"></Box>
                    ) : (
                        <EventCell
                            isMobile
                            size={`${calculateEventLength(events[counter].startTime, events[counter].endTime) * 60}`}
                            icon={events[counter].icon}
                            type={events[counter].type}
                            title={events[counter].title}
                            time={`${events[counter].startTime}h-${events[counter++].endTime}h`}
                        />
                    )}
                </React.Fragment>
            ))}
        </Flex>
    )
}

export default MobileEventsFlex
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

generateEmptyEventsCells file:

import { Event } from 'components/schedule/events/EventFlex'

export const generateEmptyEventCells = (events: Event[], eventHours: number[]) => {
    let tempFlexItems: boolean[] = []
    let tempEventHours = [...eventHours]

    //FIXME: This needs refactoring
    events.forEach((event) => {
        tempEventHours.forEach((hour) => {
            if (hour < event.startTime) {
                tempFlexItems.push(true)
            }
            if (hour === event.startTime) {
                tempFlexItems.push(false)
                tempEventHours = tempEventHours.slice(tempEventHours.findIndex((hour) => hour === event.endTime))
            }
        })
    })

    return tempFlexItems
}
export const calculateEventLength = (startTime: number, endTime: number) => {
    return endTime - startTime
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js"></script>

scheduleData file:

export const eventHours = [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
export const eventDays = [
    {
        id: 0,
        day: 'Day 1',
        weekDay: 'Monday',
        date: 'November 30th',
    },
    {
        id: 1,
        day: 'Day 2',
        weekDay: 'Monday',
        date: 'November 30th',
    },
    {
        id: 2,
        day: 'Day 3',
        weekDay: 'Monday',
        date: 'November 30th',
    },
    {
        id: 3,
        day: 'Day 4',
        weekDay: 'Monday',
        date: 'November 30th',
    },
    {
        id: 4,
        day: 'Day 5',
        weekDay: 'Monday',
        date: 'November 30th',
    },
]
export const scheduleData = [
    {
        weekDay: {
            title: 'Day 1',
            day: 'Monday',
            date: 'NOvemb 30th',
        },
        events: [
            {
                icon: '/images/icons/talk.png',
                type: 'Lecture',
                title: 'adsasd',
                startTime: 11,
                endTime: 14,
            },
            {
                icon: '/images/icons/talk.png',
                type: 'Lecture',
                title: 'adsasd',
                startTime: 15,
                endTime: 17,
            },
        ],
    },
    {
        weekDay: {
            title: 'Day 2',
            day: 'Monday',
            date: 'NOvemb 30th',
        },
        events: [
            {
                icon: '/images/icons/talk.png',
                type: 'Lecture',
                title: 'adsasd',
                startTime: 11,
                endTime: 14,
            },
            {
                icon: '/images/icons/talk.png',
                type: 'Lecture',
                title: 'adsasd',
                startTime: 18,
                endTime: 20,
            },
        ],
    },
    {
        weekDay: {
            title: 'Day 3',
            day: 'Monday',
            date: 'NOvemb 30th',
        },
        events: [
            {
                icon: '/images/icons/talk.png',
                type: 'Lecture',
                title: 'adsasd',
                startTime: 9,
                endTime: 12,
            },
            {
                icon: '/images/icons/talk.png',
                type: 'Lecture',
                title: 'adsasd',
                startTime: 14,
                endTime: 16,
            },
        ],
    },
    {
        weekDay: {
            title: 'Day 4',
            day: 'Monday',
            date: 'NOvemb 30th',
        },
        events: [
            {
                icon: '/images/icons/talk.png',
                type: 'Lecture',
                title: 'adsasd',
                startTime: 15,
                endTime: 17,
            },
            {
                icon: '/images/icons/talk.png',
                type: 'Lecture',
                title: 'adsasd',
                startTime: 18,
                endTime: 20,
            },
        ],
    },
    {
        weekDay: {
            title: 'Day 2',
            day: 'Monday',
            date: 'NOvemb 30th',
        },
        events: [
            {
                icon: '/images/icons/talk.png',
                type: 'Lecture',
                title: 'adsasd',
                startTime: 10,
                endTime: 14,
            },
            {
                icon: '/images/icons/talk.png',
                type: 'Lecture',
                title: 'adsasd',
                startTime: 15,
                endTime: 18,
            },
        ],
    },
]
Marko B.
  • 535
  • 3
  • 8
  • 18
  • I can't be sure... I had this kind of problem and I believe its related to how react watches for rerenders. By using arrays, you have to be sure that new values creates new references or it wont force a render. (either that or create something to force render) – Noriller Jun 29 '21 at 22:31
  • 1
    In React, state updates are asynchronously processed, so `events` state is still the value from the current render cycle when enqueueing the `setEmptyEventCells(generateEmptyEventCells(events, eventHours))` state update. Use an `useEffect` hook with a dependency on the `events` state to update the `setEmptyEventCells` state. – Drew Reese Jun 29 '21 at 22:48

0 Answers0