Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Root cause of state issues #7066

Closed
parisholley opened this issue Dec 31, 2020 · 5 comments
Closed

Root cause of state issues #7066

parisholley opened this issue Dec 31, 2020 · 5 comments

Comments

@parisholley
Copy link

parisholley commented Dec 31, 2020

After running into some state issues myself, I started digging through the library to figure out what the underlying issue could be. I believe the same problem is impacting the following issues:

The root cause appears to be this code here:

/*
BUG: if `event` was supplied, all previously-given `eventSources` will be wiped out
*/
function handleEventSources(inputs, context: CalendarContext) {
let unfoundSources: EventSource<any>[] = hashValuesToArray(context.getCurrentData().eventSources)
let newInputs = []
for (let input of inputs) {
let inputFound = false
for (let i = 0; i < unfoundSources.length; i += 1) {
if (unfoundSources[i]._raw === input) {
unfoundSources.splice(i, 1) // delete
inputFound = true
break
}
}
if (!inputFound) {
newInputs.push(input)
}
}
for (let unfoundSource of unfoundSources) {
context.dispatch({
type: 'REMOVE_EVENT_SOURCE',
sourceId: unfoundSource.sourceId,
})
}
for (let newInput of newInputs) {
context.calendarApi.addEventSource(newInput)
}
}

In particular, two problems:

  1. As noted in the comment, the diff'ing algorithm does not currently support passing in the events prop, it can only diff eventSources. As a result, every time a component with <FullCalendar /> is re-rendered, the event store is destroyed and recreated.

  2. Due to one, it would appear the solution would be as simple as switching to eventSources, however the problem is the diffing logic does a strict equality check, and if the object isn't the same memory reference as the previous render, it is also destroyed and recreated. so if a user started a drag, the drag'd element is referring to an event instance that was part of the old/destroyed store and the re-render can't tell you are dragging the same thing on refresh.

To solve for fullcalendar/fullcalendar-react#2, I am able to work around by implementing the following:

const eventSourceRef = useRef({ id: 'events', events });

if (JSON.stringify(eventSourceRef.current.events) !== JSON.stringify(events)) {
  eventSourceRef.current = { id: 'events', events };
}

return <FullCalendar  eventSources={[eventSourceRef.current]} ... />

useRef will guarantee that each render will get the same event source object and pass the equality check, and I only update it between renders if the JSON serialization changes.

It isn't clear the best way to implement a fix given that async functions/fetches can be part of the equation, and depending on the use cases, a full hash of the event data may be a performance hit.

@acerix acerix changed the title Root cause of a few issues Root cause of state issues Jan 4, 2021
@Ahmad-Zahid
Copy link

Any update on this?

@hamza-jutt
Copy link

Also facing this issue. Update.

@mumerfarooq000
Copy link

I am also facing this issue :/ any leads?

@FrancoRodao
Copy link

I had the same problem syncing events with a backend, the solution I found is to have a local state of the events and not sync it with the calls to the backend, at the moment I think it is the best solution.

@arshaw
Copy link
Member

arshaw commented Feb 7, 2023

The root cause has been solved in v6.1.3. See:

@parisholley , thanks for making this tracking ticket.

@arshaw arshaw closed this as completed Feb 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

No branches or pull requests

7 participants