React-Big-Calendar

£€€.T.$·2023년 9월 6일
1

React Api

목록 보기
5/7

작업물 어느정도 완성
https://github.com/fearofgod0001/ScheduleInfo


프로젝트 중 구글 캘린더 기능을 가진 달력을 찾던 중 React-Big-Calendar 가 딱 맞는 것 같아서 선택하게 됐다..... 셋팅 하기에 앞서 공식 문서를 꼭 한번 읽어 보는 것을 추천한다
react-big-calendar npm
react-big-calendar gitHub.io

틈틈히 계속 정리할 예정..!


Basic Setting

yarn add react-big-calendar
npm install --save react-big-calendar

import { Calendar, momentLocalizer } from 'react-big-calendar'
import moment from 'moment'

const localizer = momentLocalizer(moment)

const MyCalendar = (props) => (
  <div>
    <Calendar
      localizer={localizer}
      events={myEventsList}
      startAccessor="start"
      endAccessor="end"
      style={{ height: 500 }}
    />
  </div>
)

가장 기본 포맷으로 Calendar 기본 캘린더를 부르며. moment, momentLocalizer 현지의 시간을 가져온다. style을 꼭 넣어주어야 표의 크기가 나온다.

공식 문서에 나온 여러 기능을 넣을 수 있지만...

구글 캘린더의 드래그 & 드롭 기능을 너무 쓰고싶어서 좀 더 셋팅을 달리 했다. 이는 공식 깃 허브에 있으니까 참고 하도록하자!!


Drag Setting

import { Calendar, momentLocalizer } from "react-big-calendar";
import moment from "moment";
import "react-big-calendar/lib/css/react-big-calendar.css";
import withDragAndDrop from "react-big-calendar/lib/addons/dragAndDrop";

const BigCalendarInfo = () => {
  //캘린더를 DragAndDrop으로 바꿉니다.
  const DragAndDropCalendar = withDragAndDrop(Calendar);
 return (
      <DragAndDropCalendar
        localizer={momentLocalizer(moment)}
        events={myEvents}
        onEventDrop={moveEvent}
        onEventResize={resizeEvent}
        // draggableAccessor="isDraggable"
        onSelectSlot={newEvent}
        onSelectEvent={handleSelectEvent}
        resizable
        selectable
        style={{ height: 900 }}
        components={{ toolbar: Toolbar }}
      />

  );
};
export default BigCalendarInfo;

드래그를 할 수 있는 기본적인 셋팅이 끝났다.

localizer : 현지 시간 양식을 가져온다. 양식 읽어보기
events : DB혹은 파일을 읽어와 실제 달력에 뿌려 줄 데이터
onEventDrop : 위치를 Drag한 후 Drop할 때 실행되는 되는 함수
onEventResize : 이벤트의 일정을 Drag하여 Resize하는 함수
draggableAccessor : 드래그가 가능한 조건을 거는 함수로 event 값인 "isDraggable" 를 사용한다. (귀찮아서 주석처리하고 모두 다 드래그 가능하게 만듬)
onSelectSlot : 선택하여 새로운 이벤트를 넣을 수 있는 함수
onSelectEvent : 만들어진 이벤트를 선택할 때 실행되는 함수
resizable : 리사이즈를 가능하게 해준다
selectable : 선택을 가능하게 해준다

추가

onNavigate={handleDateChange} : 클릭한 날짜를 보여주는 함수 date와 같이 쓰임
date={handleDate} : 현재 날짜를 보여줄 함수
onView={handleViewChange} : 현재 위치를 바꿀 함수
view={currentView} : 현재 view 위치를 보여줌


events

기본적으로 데이터를 읽어와 달력에 뿌려주는 역할을 한다!!

양식이 정해져있는데

  {
    id: 0,
    title: 'All Day Event very long title',
    allDay: true,
    start: new Date("2023-9-13"),
    end: new Date("2023-9-13"),
  },

이런식이다!

이에 DB를 짜줄 때 해당 내용은 꼭 넣도록 하자!! allDay는 매일 반복 값 이라는 의미 이므로 빼줘도 되고 false값으로 저장해도된다!!

DB

CREATE TABLE scheduleinfo(
    id INT,
    title VARCHAR(255), 
    "start" DATE,
    "end" DATE,
    memo CLOB    
);

🔔 id값을 인식하여 drag값과 drop값을 변경하므로 꼭 primery key와 auto increase기능을 넣어주자!!!!!

memo라는 양식을 추가로 만들어서 일정에 대한 자세한 설명을 넣을 수 있도록 했다!!! (실제로 구현하진 않았음 언젠간 하겠지..)

이제 React-Query를 이용하여 DB를 가져와보자!

//유즈쿼리로 데이터를 받아옵니다.
const { data: dataOnLoadData, refetch: refetchOnLoadData } = 
useQuery("onLoadData", onLoadData);

가져올 data는 쿼리문에 맞춘 dataOnLoadData로 설정하였다.

🔔 이 때 DB에서 DATE양식은 react-big-calendar 에서 사용하는 javascript date양식과 달라서 제대로 불러오지 못하는 문제가 발생한다!!!!

//오라클 에서 들어오는 DATE 값을 JAVASCRIPT양식으로 바꿔주는 함수
function formatToJSDate(oracleDateStr) {
    return new Date(oracleDateStr);
}

//가져올 이벤트를 넣을 useState.
const [myEvents, setMyEvents] = useState([]);

//쿼리가 발생하면 데이터를 받아서 이벤트를 가져온다.
useEffect(() => {
    if (dataOnLoadData) {      
      const adjEvents = Object.values(dataOnLoadData).map((data, ind) => ({
        ...data,
        start: formatToJSDate(data.start),
        end: formatToJSDate(data.end),
      }));
      setMyEvents(adjEvents);
    }
  }, [dataOnLoadData]);

양식을 javascript의 DATE로 바꿔주며 useQuery가 실행되어 나오는 data값이 있다면 adjEvents라는 값에 map으로 돌려주어야 한다
useQuery로 반환되어 나오는 data값은 객체다!!!!!! 이에 Object.values를 사용하여 하나하나 읽어 배열로 설정한 setMyEvents에 넣어준다!!


onSelectSlot

선택한 Slot을 통해서 start날짜와 end 날짜를 지정하여 새롭게 이벤트를 등록 할 수 있게한다!!! Calendar기능의 가장 필요한 기능!! 코드를 보도록 하자!

//새로운 이벤트 입력 기능
const newEvent = useCallback((event, start, end) => {
      setMyEvents((prev) => {
        const title = window.prompt("New Event Name");
        
        mutateSubmit({
          title: title,
          start: formatToOracleDate(event.slots[0]),
          end: formatToOracleDate(event.slots[event.slots.length - 1]),
        });
        
        if (title) {
          setMyEvents((prev) => [...prev, { start, end, title }]);
        }
        
        const idList = prev.map((item) => item.id);
        const newId = Math.max(...idList) + 1;
        return [...prev, { ...event, id: newId }];
      });
    },
    [setMyEvents]
  );

이런식으로 짜주면 된다... 기본적으로 console창을찍어서 확인해보자면

prev로는 모든 일정이, 그리고 event로는 현재 설정한 일정이 나오는데 end와 start로 하지말자... end일정은 선택한 일정보다 하루 더 길게 잡힌다..(이유를 모르겠음)

대신 slots을 보면 선택한 날짜를 정확히 볼 수 있다. 이에 값을 가져오면 된다! DB에는 "YYYY-MM-DD" 양식으로 저장하고싶어 따로 formatToOracleDate 라는 함수를 만들어 설정하였다.

formatToOracleDate

  //DB에 넣을 시간양식 재포맷
  function formatToOracleDate(jsDateStr) {
    const date = new Date(jsDateStr);
    const year = date.getFullYear();
    const month = date.getMonth() + 1;
    const day = date.getDate();
    const formattedDate = `${year}-${month}-${day}`;
    return formattedDate;
  }

이에 해당 값을 insert하는 리액트 쿼리문을 작성하고 refetch 해주었다.

//새로운 값을 입력할 유즈쿼리문
const {
    data: dataSubmit,
    mutate: mutateSubmit,
    isSuccess: isSuccessSubmit,
  } = useMutation("submit", submit);

//데이터 입력이 완료되면 리패치를 하여 재랜더링 되게 한다.
useEffect(() => {
    if (isSuccessSubmit && dataSubmit) {
      console.debug("## submit refetch => ", ataSubmit);
      refetchOnLoadData();
    }
  }, [isSuccessSubmit, dataSubmit, refetchOnLoadData]);

useMutation 의 isSuccess 는 boolean형 타입으로 true값을 반환한다. 조건문에 넣어 refetch해주자!

profile
Be {Nice} Be {Kind}

0개의 댓글