fullcalendar: FullCalendar shows events duplicated on modification

Reduced Test Case

https://codesandbox.io/s/zealous-jepsen-190d2?file=/src/DemoApp.jsx

Bug Description

If I press down on an event, move it, release the mouse button, press the mouse button again, -> can drag a copy of the event

Screenshots

From the minimal working example event_duplication

In the app, with some more hooks/delay it works close to every time. The title is rendered as the title is calculated in eventDidMount duplication_from_app

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 2
  • Comments: 20 (5 by maintainers)

Most upvoted comments

when merging the new event into with the running events array, don’t just merge in an EventApi object, use EventApi::toPlainObject instead…

https://codesandbox.io/s/quirky-nightingale-vr1k1?file=/src/DemoApp.jsx

https://fullcalendar.io/docs/Event-toPlainObject

@arshaw I still have the issue with your solution (even in your codesandbox). Please, try to drag and drop an event into a different time slot and immediately after dropping the event, re-drag it (within the 2 seconds) to another time slot without dropping it, you will see that the event is still duplicated.

This issue occurs exactly when you are dragging an event, at the same time that a React setState occurs in the background (in this case in the setTimeout callback). This causes a render of the component. Thus, the events given to FullCalendar through the events props are displayed again.

When the render occurs, it is like the moving event is unsync with the initial dragging event when a render occurs during the move. Thus, when dropping, FullCalendar creates a broad new event.

Same issue on fullcalendar-vue 5.3.0

ezgif com-gif-maker

In my case, this code is used on every eventDrop:


        async onEventDrop(data)
        {
            var end = data.event.end;
            if(end == null)
            {
                end = dayjs(data.event.start).toDate();
            }

            this.changeDate(data.event, data.revert);
        },

        async changeDate(event, revert)
        {
            try
            {
                await $.post({
                    url: Routing.generate('calendar_changedate'),
                    data: {
                        id: event.id,
                        start: dayjs(event.start).format("YYYY-MM-DD HH:mm"),
                        end: dayjs(event.end).format("YYYY-MM-DD HH:mm"),
                        isAllDay: false
                    }
                });
            }
            catch(e)
            {
                revert()
            }
        },

Edit:

I also checked your react example @arshaw , and it still duplicates:

image

This problem has been fixed in v6.1.3

Updated repro and ported to stackblitz: https://stackblitz.com/edit/github-yxh8xk?file=README.md

In order to prevent this bug, developers are responsible for the following:

  • Ensuring a unique id property on each event. This functions like React’s key property. It correlates same items between rerenders.
  • If you are spreading and EventApi’s properties in an object (for giving data to a redux store for example), use toPlainObject before spreading the props.

I plan to add this to official docs very soon.