修复React中完整日历中的重复事件

问题描述 投票:0回答:3

我正在使用 fullcalendar.io 开发日历, 但有一个问题。 如果将计划从“待办事项”列表拖放到日历中,则日历上会出现两个重复的事件。 随着状态的更新,日历上会显示一个,默认提供的也会显示出来,所以两者是重叠的。 我该如何解决这个问题?

这是我的代码:

import React,{useEffect,memo, useRef, useState} from 'react';
import Fullcalendar from '@fullcalendar/react';
import dayGridPlugin from '@fullcalendar/daygrid';
import interactionPlugin,{Draggable} from '@fullcalendar/interaction';
import styled from 'styled-components';
import { event } from 'jquery';

const Container  =  styled.div`
    
display:flex;
justify-Content: space-around;
alignItems:start;

    & .calendar{
        width:60%;
        height:auto;
    }
    & .Todo{
        width:300px;
            & h2{
                text-align:center;
            }
    }
`




// 이벤트 Todolist 에서 drag n drop 기능
    const ToDoList = memo(({event})=>{
        const elRef = useRef(null);
        
        useEffect(() => {
            const draggable = new Draggable(elRef.current, {
            eventData: function () {
                return { ...event, create: true };

            }
            },[]);
        
            return () => draggable.destroy(event);
        });
        return (
            <div
              ref={elRef}
              className="fc-event fc-h-event mb-1 fc-daygrid-event fc-daygrid-block-event p-2"
              title={event.title}
              style={{
                marginTop:"10px",
                cursor: "pointer",
                background:"#8b00ff",
                border:" none",
                padding:"5px",
              }}
            >
              <div className="fc-event-main">
                <div>
                  <strong>{event.title}</strong>
                </div>
              </div>
            </div>
          );
    
    });





function Calendar(){

    const calendarRef = useRef()

    // 캘린더 안에 들어있는 이벤트들 
    const [CalEvents, setEvents]  = useState([ 
        {
            id : 2341, 
            title: '학원 수업',
            color: 'red',
            start: '2021-10-19T11:00',
            end: '2021-10-19T13:00',
            constraint:'학원 수업'  // event 수정 제한
        },
        {
            id : 57124,
            title: '학원 수업',
            color: 'red',
            start: '2021-10-21T11:00',
            end: '2021-10-21T13:00',
            constraint:'학원 수업'  // event 수정 제한
        }
    ]);

    window.calevent = CalEvents;

    // Todolist 안에 들어있는 이벤트들
    const [Todo , setTodo]  = useState([
        {
            title:"과제 1 단어",
            id: 14351,
            start:' ',
            end: ' ',
            color:"#8b00ff",
        },
        {
            title:"수능 특강 풀기",
            id: 14203,
            start:' ',
            end: ' ',
            color:"#8b00ff",
        },
        {
            title:"개념 복습하기",
            id: 15151,
            start:' ',
            end: ' ',
            color:"#8b00ff",
        },
        {
            title:"모의고사1 다시 풀기",
            id: 16131,
            start:' ',
            end: ' ',
            color:"#8b00ff",
        },
        {
            title:"오답노트 쓰기",
            id: 15678,
            start:' ',
            end: ' ',
            color:"#8b00ff",
        }
    ]);

    // TodoLIst에서 캘린더로 드롭 후 State 업데이트 함수
    const handleDrop = (info) => {
        
        const new_start = info.event.startStr;
        const new_end = info.event.endStr;
        const NewEvent ={
     
            id:info.event.id,
            title:info.event.title,
            color:"#8b00ff",
            start: new_start,
            end:new_end,
            
        }
        //  state 변경해주기
        const DropList = CalEvents.concat(NewEvent);
        setEvents(DropList);
        console.log(CalEvents)
        CalEvents.addEventSource( NewEvent )
    }







    return(
        <Container>
            <div className="calendar">
                <Fullcalendar
                id="fullcalendar"
                plugins={[dayGridPlugin,interactionPlugin]}
                initialView = "dayGridMonth"
                selectable={true}  // 달력에서 드래그로 날짜 선택 
                editable={true} // 캘린더 내에서 일정 옮기고 수정  
                locale='ko' // 한국어 설정
                dayMaxEvents={true} // 하나의 날짜에 이벤트 갯수 제한 넘어가면 more로 표시 
                businessHours={true} // 주말 색깔 블러 처리
                events ={CalEvents} // calendar event 불러오기
                eventReceive = {handleDrop} // Todolist 에서 event를 드롭했을 때 state 업데이트
  
                
                
                />
             </div>

             <div className="Todo">
                 <h2>To Do List</h2>
                    <div className="list">
                        {Todo.map((event,index)=>{
                            return(
                            <ToDoList key ={index} event={event}/>
                        )})}
                    </div>
             </div>


        </Container>


    )
}

export default Calendar;
javascript reactjs fullcalendar
3个回答
0
投票

在使用 FullCalendar(使用 React,尽管这可能不是特定于 React)、拖放事件创建以及某种数据存储来保存事件时,我遇到了完全相同的问题(在这种情况下,您使用的是 React State)为了这)。经过一番挖掘,以下是导致您看到重复事件的原因:

  1. 从存储中加载事件并将它们传递到 FullCalendar 的
    events
    反应道具以显示日历
  2. 当新的外部事件被拖放到日历上时,FullCalendar 会创建一个新事件并将其添加到自己的内部事件存储中。同时,您可以使用自定义
    id
    值将事件添加到您自己的数据存储中。
  3. 一切看起来都很好(只有一个事件可见),直到刷新数据源并将新数据传递到 fullcalendar 的
    event
    属性中。 FullCalendar 可能会获取此数据并将其与自己的现有数据合并,使用
    id
    字段进行重复数据删除。
  4. FullCalendar 看到同一天的两个事件,一个具有之前创建的默认
    id
    “”(空字符串),另一个具有您的自定义
    id
    值,并得出结论它们必须不同,因此它两者都显示

最简单的解决方案

解决此问题的最简单方法可能是确保当您调用

new Draggable()
时,确保您的
eventData
提供正确的
id
值,该值将唯一标识该事件并与数据库中的该事件匹配活动。

这将确保当 FullCalendar 尝试对删除事件时创建的事件与它看到的来自您自己的数据存储的新事件进行重复数据删除时,id 匹配。

替代解决方案

如果您拖放的项目代表事件以外的其他内容(例如 TODO 项目、时间表、人员或任何其他可以拖动到多个日期的项目),您可能无法仅使用来自该非事件对象的 ID,因为即使您从该对象创建两个日历事件,ID 也将相同(这意味着该 id 不再唯一,fullcalendar 可能会删除您的其中一个事件)。

确保您的事件具有唯一的 id 之后,您可以使用 React 界面中提供的 FullCalendar 的

eventsSet
属性。

只要任何事件发生变化(通过拖放或因为

events
属性更改值而消失),就会调用此函数。调用它时,会向它传递 FullCalendar 知道的每个事件的列表。这是添加的好地方一些你自己的重复数据删除逻辑。例如,这是我的这个函数的版本:

eventsSet={(arg: EventApi[]) => {

    for (const event of arg) {
        //see how many events are set for the same day as this particular event
        let argsThisDay = arg.filter((value) => value.startStr == event.startStr)
        let argsThisDaycount = argsThisDay? argsThisDay.length: undefined;
        // if more than one event is present for today, and this event has an empty ID (i.e. it was created automatically by FullCalendar) we don't need it anymore as there is already another event covering this day
        if (argsThisDaycount == 2 && event.id == "") {
            event.remove()
        }
    }
}}

注意 此功能可能不适合您,因为我的应用程序将日历上的项目限制为每天一个。如果您的需求不同,您可能需要自定义


0
投票

我在文档中发现,如果您想在重新获取时删除 fullcalndar 的内部缓存数据,则每当您通过 true

 添加新事件时,都必须指定 
源 id
addEvent


0
投票

我在 FullCalendar github 页面上找到了这个问题的答案: https://github.com/fullcalendar/fullcalendar-react/issues/118

用户arshaw创建了一个令人惊叹的codesandbox,可以轻松解决这个问题: https://codesandbox.io/s/fullcalendar-react-draggable-forked-ehr0h?file=/src/App.js

这不是我的解决方案,但它有效!额外的好处是,这是用反应钩子而不是类组件编写的,这在 FullCalendar 示例中非常罕见!这是我的新转到页面。

© www.soinside.com 2019 - 2024. All rights reserved.