'Why does useEffect React Hook not work properly with dependency?
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
).
Solution 1:[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)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Scorpia |