ReactNoob
ReactNoob

Reputation: 3

fullcalendar react eventclick modal useState to set event.id not working

Problem Context: Currently using FullCalendar v6.1.8 and react-Bootstrap 5.2.3 to display events from an API JSON url (with or without Axios). The calendar and events load just fine. However, using eventClick to set the boolean display state of the modal and setting the single event data to state, causes FullCalendar to refetch. On screen in the background while the modal displays, the background events jump as the refetch happens which is very disrupting. And so to control the fetching of data, I've changed to code to use Axios. However, when data comes back from FullCalendar via handleClick, I cannot get the event.id as it returns "undefined", thereafter on subsequent clicks, the setEventId() works but it uses the prior event's id. I think I am missing a way to incorporate some sort of hook, useState, or useMemo to wait for the cycle, fullcalendar loads --> getEventsData() --> fullcalendar eventclick. But I've spent three days looking for answers and testing a variety of code and can't quite put my finger on it.

Troubleshooting: Naturally I've searched SO and the web, reviewed similar reports but its obvious that my knowledge of React and FullCalendar aren't quite there yet to resolve this. If I can't resolve it, I may have to abandon FullCalendar. In code, I have fed the Json API to events, eventSources but the refetch still happens. So, then I though I would feed a function to FullCalendar. I did it first with a plain function, then with Axios and useEffect. With Axios and useEffect, I can effectively control the fetch and refetch. But now the problem is that when FullCalendar returns data from "eventClicked", I cannot use a useState() to set the single data event to a const.

const Calendar = () => {

  const[URL, setURL] = useState("events")
  const[error, setError] = useState("")
  const[loading, setLoading] = useState(false)
  const[isModalOpen, setIsModalOpen] = useState(false)
  const[eventId, setEventId] = useState([])
  const[events, setEvents] = useState([])

  const[urlParms, setUrlParms] = useState({
    start: new Date(),
    end: new Date().tosISOString(),
  })

  useEffect(() => {
    getEventsData()
  }, [URL, urlParms])

  const getEventsData = async function () {
    setLoading(true)
    urlParms.start.setDate(0)
    try {
      const response = await 
              axiosAPI.get(URL + 
              `/?start=${urlParms.start.toISOString()
               &end=${urlParms.end}}`)
      if (response && response.data) {
          setEvents(response.data)
          setLoading(false)
      }
    } catch (error) {
        console.log(error)
    }
  }

  const reservations = useMemo(()  => {
    let filteredResult = []
    if (events !== undefined) {
       filteredResult = events
    }
    return filteredResult
  }, [events])

  function handleEventClick(calData) {
    console.log(calData.event.id) /* This outputs fine the id of clicked event */
    setEventId(calData.event.id) /* This assignment fails the first time,
                                    thereafter it assigns the prior id. */
    console.log(eventId)         /* This outputs blank the first time */ 
  }

  return (
    <div>
     <FullcAlendar
      /* Other basic options are set here. Omitted for brevity. */
       events={reservations}
       eventClick={(calData) => handleEventClick(calData)}
     />
    </div>
   )


}

Upvotes: 0

Views: 653

Answers (1)

Jason Ming
Jason Ming

Reputation: 559

function handleEventClick(calData) {
    console.log(calData.event.id) /* This outputs fine the id of clicked event */
    setEventId(calData.event.id) /* This assignment is succeeded */
    console.log(eventId)         /* But you will still see the prev eventId, because React don't update states immediately */
}

// If you want to do something after setting new state, you can use useEffect to track the new state.
useEffect(() => {
  console.log(eventId); // Updated eventId
}, [eventId];

Upvotes: 0

Related Questions