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



我正在使用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;

我在使用FullCalendar(与React一起,尽管这可能不是特定于React),拖放事件创建和某种类型的数据存储来持久化事件时也遇到了同样的问题(在这种情况下,您使用的是React state)。经过一番深入研究,以下是导致您看到重复事件的原因:

  1. 从存储中加载事件并将它们传递给FullCalendar的eventsreact prop以显示日历
  2. 当一个新的外部事件被拖放到日历中时,FullCalendar创建一个新事件并将其添加到自己的内部事件存储中。同时,您可以使用自定义id值将事件添加到自己的数据存储中。
  3. 一切看起来很好(只有一个事件是可见的),直到你的数据源被刷新,新的数据被传递到fullcalendar的event道具。FullCalendar可能会获取这些数据并将其与自己的现有数据合并,使用id字段来重复数据删除。
  4. FullCalendar在同一天看到两个事件,其中一个的默认id为"(空字符串),另一个与您的自定义id值,并得出结论,他们必须是不同的,所以它显示

最简单的解决方案

解决这个问题的最简单的方法可能是确保当你调用new Draggable()时,确保你的eventData提供了一个正确的id值,该值将唯一地标识该事件,并与数据库中该事件的内容相匹配。

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

替代解决方案

如果你拖放的物品代表其他东西,而不是一个事件(比如一个TODO项,一个时间表,一个人,或任何其他可以拖到多个日期)你可能不能够只使用一个ID从影响对象的ID将是相同的,即使你从该对象创建两个日历事件(这将意味着ID不再是独特而fullcalendar可能会删除你的事件)。

在确保你的事件有唯一的id之后,你可以使用FullCalendar的eventsSetprop,它在react接口中可用。

当任何事件发生变化(通过拖放或因为eventsprop改变值而消失)时,该函数被调用。当它被调用时,它被传递给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()
}
}
}}

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

最新更新