You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中FullCalendar接收拖拽事件时重复创建多实例问题

日历拖拽创建事件重复生成问题

在React中实现了日历功能,支持从侧边栏容器拖拽用户到日历上创建预约事件。事件更新(调整大小、拖拽移动)功能正常,但触发eventReceive事件时,会重复创建多个仅ID不同的相同事件:初始生成3个,之后依次递增为4个、5个;若编辑已创建的事件,下次触发eventReceive时生成的实例数量会额外增加编辑次数,比如原本应生成4个,编辑后会生成5个,后续持续递增。

日历组件代码

const Calendar = ({ ToSaveEvents, uid, ToSaveEventsList }: any) => {

  const [events, setEvents] = useState<TrueCalendarEvent[]>([])
  const CalRef = useRef<FullCalendar>(null)

  useEffect(() => {
    const db = getDatabase(app)
    const unsub = onValue(ref(db, `users/${uid}/CalendarEvents`), (snapshot) => {
       ///获取已保存的事件用于展示或检测变更
      }
    })

    return () => {
      unsub()
    }
  }, [])


  const InCalendarUpdate = useCallback((info: EventResizeDoneArg | EventDropArg) => {

    const { event } = info
    if (events.find(ev => ev.id === event.id)) {
      const db = getDatabase(app)
      remove(ref(db, `users/${uid}/CalendarEvents/${event.id}`))
      ToSaveEvents((prevEvents: any) => {
        return [...prevEvents, event]
      })
    }
    const updatedEvent = {
      title: info.event.title,
      start: info.event.start ? info.event.start.toISOString() : null,
      end: info.event.end ? info.event.end.toISOString() : null,
      color: "#D7C627"
    }

    ToSaveEvents((prevEvents: any) => {
      return prevEvents.map((ev: TrueCalendarEvent) => {
        const { extendedProps, ...lastev } = ev
        return ev.id == event.id ? { ...lastev, ...updatedEvent, extendedProps: { ...extendedProps, lastevent: (extendedProps.lastevent == null ? lastev : extendedProps.lastevent) } } : ev
      })
    })


    info.event.remove();
  },[])

  const handleEventReceive =  useCallback((info: EventReceiveArg) => {

    const defaultEndTime = new Date(info.event.start!.getTime() + 60 * 60 * 1000).toISOString()

    const newEvent = {
      id: info.event.id,
      title: info.event.title,
      start: info.event.start ? info.event.start.toISOString() : null,
      end: info.event.end ? info.event.end.toISOString() : defaultEndTime,
      color: "#D7C627",
      extendedProps: { lastevent: null, ToID: info.event.extendedProps.ToID }
    };

    ToSaveEvents((prevState: any) => {
      return [...prevState, newEvent]
    })

    info.event.remove();
  },[])


  useEffect(() => {

    if (CalRef.current) {
      const Calapi = CalRef.current.getApi()


      Calapi.setOption("eventReceive", undefined)
      Calapi.setOption("eventResize", undefined)
      Calapi.setOption("eventDrop", undefined)


      Calapi.setOption("eventReceive", handleEventReceive)
      Calapi.setOption("eventResize", InCalendarUpdate)
      Calapi.setOption("eventDrop", InCalendarUpdate)
    }
  }, [InCalendarUpdate,handleEventReceive])

  return (
    <FullCalendar
      plugins={[dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin]}
      initialView="timeGridDay"
      events={[...events, ...ToSaveEventsList]}
      editable={true}
      droppable={true}
      headerToolbar={{ left: 'prev,next today', center: 'title', right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth' }}
      ref={CalRef}
    />
  );
};

侧边栏组件代码

const SidebarDoctor = ({ uid }: any) => {
  const [users, changeUsers] = useState<any>([])

  const [doctorfirstname, changedoctorfirstname] = useState<string>("")
  const [doctorlastname, changedoctorlastname] = useState<string>("")

  useEffect(() => {
    const db = getDatabase(app)
    const fetchname = async () => {
          ///调用Firebase数据库获取数据
    }
    fetchname()

    const unsub = onValue(ref(db, `users/${uid}/notifs`), async (snapshot: any) => {
        ///调用Firebase数据库获取数据

    })
    return () => {
      unsub()
    }
  }, [])

  const UsersRef = useRef(null)

  const DragableElements = UsersRef.current
  if (DragableElements) {
    new Draggable(DragableElements,
      {
        itemSelector: '.user-item',
        eventData(eventEl) {
          const id = uuidv4()
          const firstlastnamePacient = eventEl.dataset.firstname + " " + eventEl.dataset.lastname
          const firstlastnameDoctor = doctorfirstname + " " + doctorlastname
          const lastevent: CalendarEvent = {
            id: "",
            title: "",
            start: "",
            end: "",
            color: ""
          }
          const ToID = eventEl.dataset.id
          return {
            id,
            title: firstlastnamePacient + " appointment to " + firstlastnameDoctor,
            extendedProps: { lastevent, ToID: ToID }
          };
        },
      });
  }

  return (
    <div className="sidebar">
      <div id="users-list" ref={UsersRef}>
        <h4>Users</h4>
        {users.map((user: any) => {
          return <div
            key={uuidv4()}
            data-id={user.id}
            style={{ marginBottom: '5px' }}
            className="user-item fc-event"
          > {user.firstname + " " + user.lastname} </div>
        })}
      </div>
    </div>)
}

内容的提问来源于stack exchange,提问作者No0bYebY

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 20:03:18