[React] 자바스크립트로 캘린더 만들기(라이브러리 사용 X)

박세화·2023년 7월 26일

React JS

목록 보기
15/22

디자인 시안과 똑같은 캘린더를 만들고 싶었는데, 라이브러리를 사용하면 스타일 적용이 불가능할 것 같아서 아예 자바스크립트로 새로이 만들었다. 참고 블로그 의 코드를 거의 똑같이 따라 작성한 것에 불과하지만 그 과정에서 나도 바닐라 자바스크립트를 많이 배웠다. 더 나아가 이 글이 또 다른 누군가에게 도움이 되길 바라며 쓰는 글!

(그림이...😅)
달과 연도가 있는 RenderHeader, 요일이 있는 RenderDays, 날짜가 있는 RenderCells로 컴포넌트를 나눌 것이다.

RenderHeader

export const RenderHeader = ({ currentMonth, prevMonth, nextMonth }: headerProps) => {
    return (
      <CalHeader className="header row">
        <div className="col col-1">
          <Expand onClick={prevMonth} />
        </div>
        <MonthYear className="col col-2">
          <span>
            <span>{format(currentMonth, "M")} </span>
            {format(currentMonth, "yyyy")}
          </span>
        </MonthYear>
        <div className="col col-3">
          <Expand onClick={nextMonth} />
        </div>
      </CalHeader>
    );
  };
  • 긴 한개의 row에 세 개의 column이 들어있는 구조이다. column엔 차례로 뒤로이동 아이콘(이전 달로 이동), 달+연도, 앞으로 이동 아이콘(다음 달로 이동) 가 들어있다.

RenderDays

export const RenderDays = () => {
  const days = [];
  const date = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];

  for (let i = 0; i < 7; i++) {
    days.push(
      <Days className="col" key={i}>
        {date[i]}
      </Days>
    );
  }

  return <div className="days row">{days}</div>;
};
  • 만약 블로그의 도움 없이 나 혼자 코드를 짰다면 이 부분을 리턴 부분에서 배열을 매핑해서 차례차례 컴포넌트로 뱉어내는 방식으로 했을텐데, 이 코드에선 for문으로 6번을 돌려 빈 배열에 컴포넌트를 하나씩 추가해주고, 그 배열을 바로 리턴하는 방식이었다. 새로운 방법을 배웠다!

RenderCells

const Cells = styled.div`
  font-size: 1rem;
`;

const DayBox = styled.div`
  padding: 0;
  width: fit-content;
`

type dayprops = {
  display: string;
};

const Day = styled.span<dayprops>`
    display: ${(props) => (props.display === 'true' ? "block" : "none")};
`;

export const RenderCells = ({
  currentMonth,
  onDateClick,
}: headerProps) => {
  const monthStart = startOfMonth(currentMonth);
  const monthEnd = endOfMonth(monthStart);
  const startDate = startOfWeek(monthStart);
  const endDate = endOfWeek(monthEnd);

  const rows = [];
  let days = [];
  let day = startDate;
  let formattedDate = "";

  while (day <= endDate) {
    for (let i = 0; i < 7; i++) {
      formattedDate = format(day, "d");
      const cloneDay = day;

      days.push(
        <DayBox className="col cell">
          <Day display={isSameMonth(day, monthStart) ? 'true' : 'false'}>
            {formattedDate}
          </Day>
        </DayBox>
      );
      day = addDays(day, 1);
    }

    rows.push(<div className="row">{days}</div>);

    days = [];
  }

  return <Cells className="cells">{rows}</Cells>;
};
  • monthStart : 현재 날짜가 속한 달의 첫 날
    monthEnd : 현재 날짜가 속한 달의 마지막 날
    startDate : monthStart가 속한 주의 첫 날
    endDate : monthEnd가 속한 주의 마지막 날

  • 먼저 for문을 이용해 days 배열에 startDate부터 시작해서 7개씩 날짜를 넣는다. 변수 day의 최초값은 startDate이며, 배열에 push된 후 1씩 증가한다.

  • days가 7개로 가득 차면 for문이 종료되며 rows 배열에 days가 통째로 들어간다. 그리고 days는 비워진다.

  • dayendDate와 같아지면 while문이 종료되며, 전체 rows 배열이 리턴된다.

  • 이전/다음 달의 날짜는 표시하고 싶지 않아서 isSameMonth 메소드를 이용해서 조건부 스타일링을 했다. (display none을 쓰면 웹 접근성을 무시하게 된다는데 일단 넘어가고 다음에 다시 알아볼래...)

  • 이런 구조가 된다.

👀 scss 파일이 연결이 안되어있는데 grid가 어떻게 적용되는지 모르겠어서 참고 블로그에 문의해놓았음

0개의 댓글