2

I'm working at a React Web App with Fullcalendar. I think one does not need to know Fullcalendar in order to answer this question. It's rather a matter of React understanding.

Long story short, Fullcalendar has an api that refetches any events from a given source. In my case, my source is state.events, iniated with useState. I only want to refetch, when my state changes. All good so far. However, at the first initial render, Fullcalendar is not able to fetch anything.

const OverviewPage: React.FunctionComponent<IOverviewPageProps> = (props) => {
    const calendarRef = useRef<any>();
    const [sourceAPI, setSourceAPI] = useState<any>(undefined);
    const [state, setState] = useState<State>({
        externalEvents: [],
        events: []
    });
   
useEffect(() => {
         if (calendarRef.current !== undefined) {
            let calendarApi = calendarRef.current.getApi();

            if (sourceAPI === undefined) {
                const source = calendarApi.addEventSource(state.events);
                source.refetch()
                setSourceAPI(source);
            } else {
                sourceAPI.refetch();
            }
        }
    }, [state])
return (<div>
           <FullCalendar
               ref={calendarRef}
               //other props
           />
        </div>)
;

Now, as you can see, as long as I don't have the reference of the calendar, I can't iniate the calendarApi. And as long as I don't have that api, I can't refetch. I do have to mention, when I take away the useEffect dependency (state), I no longer face an issue with fetching the events (even on the initial render). However, that causes other issues in my code that I wasn't able to fix, so I rather prefer to fix it with useEffect.

Update

It was requested to explain more in depth, what is happening in the code. Fullcalendar needs a source of events (calendar tasks). To provide this source, one has to iniate it before render, which I'm doing here in useEffect

Checking, if the reference to the element Fullcalendar already exists to prevent a render error

if (calendarRef.current !== undefined) {//...}

Checking, if a source was already added. If no, iniate a source by using Fullcalendar's api. .addEventSource adds a source that contains an array of objects (events) - in this case state.events - and returns a Fullcalendar Source so that I can interact with it later (e.g. refetch). .refetch() simply takes the content of the source and (re-)renders them on the calendar (so in other words the content of state.events). I then store this Fullcalendar Source in a React State so that I can interact with the same source later again, without having to reiniate it again.

 if (sourceAPI === undefined) {
                const source = calendarApi.addEventSource(state.events);
                source.refetch()
                setSourceAPI(source);
            }

If a Fullcalendar Source is already existing, apply the refetch call again.

else {
        sourceAPI.refetch();
}

There's really not more to say about Fullcalendar. I was suspecting the issue in React State management and that I'm doing something wrong there (with useEffect).

ADyson
  • 57,178
  • 14
  • 51
  • 63
Scorpia
  • 375
  • 4
  • 15
  • Can you provide the Code for your fetching functions? – ivanatias May 04 '22 at 20:27
  • it's not my function, it's provided by `Fullcalendar` as an api call. – Scorpia May 04 '22 at 20:46
  • What does this calendar API do with the values you are passing it from React? What does `addEventSource` and `refetch` do? What are you expecting to happen? CAn you more precisely explain the issue? Can you "walk" us through the code and explain each piece and also provide the exact steps to reproduce any issues you are seeing? – Drew Reese May 05 '22 at 05:47
  • @DrewReese I've updated my post as requested. I was expecting some sort of error in the way I'm handling `useEffect` hence not explaining `Fullcalendar` in depth. – Scorpia May 05 '22 at 06:19
  • I'm guessing the issue is that you are updating the `state.events` state but the calendar code isn't seeing any updated state? As far as I can tell, this appears to be a stale enclosure over the `state.events` value that was passed to `calendarApi.addEventSource`. – Drew Reese May 05 '22 at 06:33
  • @DrewReese What I don't understand, I thought when using `useEffect` with `dependency`, the corresponding `useEffect` is only triggered once the corresponding `dependency` (the `state`) has been updated completely right? I checked now with `console.log` and basically on startup of the program/page, it triggers `useEffect` twice and both times `calendarRef` is `undefined`. Once started, switching to another page and back, `calendarRef` is no longer `undefined` and the `source` is mounted / events rendered. – Scorpia May 05 '22 at 07:13
  • `useEffect` hook with dependency, the effect's callback is called at the end of the initial render, and any time any of the dependencies update. There was a change to the `React.StrictMode` component in React 18 that mounts the component twice and keeps the result of the first mount. See [Ensuring reusable state](https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state). This isn't what I'm referring to though. The state is only passed to the calendar code once when it is instantiating a source. Can you link some documentation on this `Fullcalendar` library? – Drew Reese May 05 '22 at 07:19
  • @DrewReese Thanks for your help, very much appreciated. Here's a link to the library in terms of `React`. Scroll down to the chapter `Calendar API`: https://fullcalendar.io/docs/react - And here's a link in regards of mounting `sources`: https://fullcalendar.io/docs/event-source – Scorpia May 05 '22 at 07:25
  • Do you just need to call `calendarApi.addEventSource` each time the `state` updates? I don't quite understand the source stuff since it doesn't appear to be used at all. – Drew Reese May 05 '22 at 07:48
  • @DrewReese I finally was able to figure it out. I answered my question in case someone else has a similiar issue in the future. You're right, `.addEventSource` is not important each time `state` updates. It's just important that `.addEventSource` is triggered once and max once, so that `.refetch()` can be called when the `state` does update. – Scorpia May 05 '22 at 07:50
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/244495/discussion-between-scorpia-and-drew-reese). – Scorpia May 05 '22 at 07:56

1 Answers1

1

After trying out multiple different approaches, I finally managed that Fullcalendar also renders events on the first initial render. This might be helpful for people in the future, facing the same issue with React and Fullcalendar

const OverviewPage: React.FunctionComponent<IOverviewPageProps> = (props) => {
    const calendarRef = useRef<any>();
    const [sourceAPI, setSourceAPI] = useState<any>(undefined);
    const [state, setState] = useState<State>({
        externalEvents: [],
        events: []
    });
useEffect(() => {
        if (sourceAPI === undefined && calendarRef.current !== undefined) {
            const calendarApi = calendarRef.current.getApi();
            const source = calendarApi.addEventSource(state.events);
            setSourceAPI(source);
        }
    });
   
useEffect(() => {
        if (sourceAPI !== undefined) {
            sourceAPI.refetch();
        }
    }, [state]);

return (<div>
           <FullCalendar
               ref={calendarRef}
               //other props
           />
        </div>)
;

Pay attention that the first useEffect is triggered every time while the second one is only triggered when there was a change in regards of its dependency. This way, the source is initiated for sure, which it appeared to be the main problem with the privious code (calendarRef.current was always undefined on initial start/render)

Scorpia
  • 375
  • 4
  • 15