티스토리 뷰

 

*피드백은 언제나 환영합니다🙌

 

 

 

GIthub Pages로 배포까지 마치고 코드를 어떻게 짰었는지, 수정할 건 없는지 보던 와중에 휴식 탭 대신에 달력을 넣기로 결정했다. 이유는 유튜브 영상보다 투두리스트+타이머 기능이 들어있는 생산성 웹 페이지라는 큰 틀에 걸맞게(?) 달력을 넣는게 훨씬 나을 것 같다고 생각했기 때문이다. 가능하다면 작게나마 일정을 추가할 수 있게 만들어보려고 한다.

 

 

 

달력 만들기


 

 

1. 설치 및 날짜 설정하기

 

먼저 npm create-react-app [프로젝트명]을 사용해서 react 파일을 생성해준다.

나는 기존 프로젝트가 있어서 따로 생성하지 않았다.

 

 

다음으로 캘린더를 만들기 위한 핵심 라이브러리인 moment.js를 설치해준다.

moment.js는 JavaScript에서 날짜 및 시간을 조작하고 작업하는데 도움이 되는 JavaScript 라이브러리다.

이외에도 날짜 및 시간을 조작하는 라이브러리는 Luxon.js, date-fns.js 등 여러가지가 있다.

 

npm install moment --save

 

 

 

 

 

 

 

moment.js 를 사용해서 today.format으로 현재 연도 및 달을 표시했다.

 

import {useState} from 'react';
import moment from 'moment';

function Calender() {
  const [getMoment, setMoment] = useState(moment());
  const today = getMoment; // today == moment()

  return(
    <div>
      <button>이전달</button>
      <span>{today.format('YYYY년 MM월')}</span>
      <button>다음달</button>
    </div>
  )
}

export default Calender;

 

 

 

 

 

위 처럼 코드를 짜면 아래와 같이 화면이 나온다. 

사이트를 찾아보면 moment()를 사용하는 방법이 나오는데 나는 https://jsikim1.tistory.com/195 를 참고했다.

 

 

 

 

 

 

 

subtract은 빼기 add는 더하기다. 따라서 원하는 날짜 단위를 선택해서 더하고 빼면 된다.

 

{moment().calendar()}
{moment().subtract(10, 'days').calendar()}
{moment().add(10, 'days').calendar()}

 

 

 

다음으로 useState를 사용해서 버튼을 누르면 달이 변하도록 설정했다.

 

 

 

* 날짜를 더하거나 뺄 떄 생길 수 있는 문제점

한개의 moment 변수를 기준으로 날짜를 연속적으로 더하거나 빼게 되면 해당 변수도 add or subtract 함수를 실행하는 도중 값이 변하게 된다. 

 

let now = moment("2023-02-28");
console.log(now.add(3, "days")); // 2023-03-03
console.log(now.subtract(5, "days")); // 2023-02-26
console.log(now); // 2023-02-26

 

 

 

따라서 add나 subtract를 하기 전에 clone() 함수를 사용하면 된다. 

 

<button onClick={()=> {setMoment(getMoment.clone().subtract(1, 'month')) }}>이전달</button>
<span>{today.format('YYYY년 MM월')}</span>
<button onClick={()=> {setMoment(getMoment.clone().add(1, 'month')) }}>다음달</button>

 

 

 

 

 

 

 

2. 캘린더 만들기

 

 

1) 첫 주와 마지막 주에 대한 설정

 

firstWeek는 startOf('momth') 그 달의 시작하는 week() 주 이고 lastWeek는 endOf('momth') 그 달의 끝나는 week() 주 이다.

 

lastWeek에서는 조건문을 사용했다.

1년은 52주이고 며칠이 더 있는데 달력은 53주로 표현해야 하지만 moment()는 내년의 첫주인 1로 표시한다.따라서 마지막 주가 1이라면 53으로 표시되도록 했다.

const firstWeek = today.clone().startOf('month').week();
const lastWeek = today.clone().endOf('month').week() === 1 ? 53 : today.clone().endOf('month').week();

 

 

 

 

 

 

 

2) 반복문 이용해서 배열 만들기

 

react에서는 배열을 아래처럼 표시하면 배열 내의 요소를 웹에 표시해준다.

 

 const arr = [1, 2, 3, 4, 5];
  
  return (
    <div className="App">
        <table>
          <tbody>
            {arr}  // 웹에 12345 가 표시된다.
          </tbody>
        </table>
    </div>
  );

 

 

 

이 방식을 바탕으로 반복문을 이용해서 테이블을 만들었다.

해당 달의 총 주 수만큼 반복문을 실행하고 테이블의 내용을 배열에 추가했다.

 

function calenderArr() {
    let result = [];
    let week = firstWeek;
    for( week; week <= lastWeek; week++ ) {
      result = result.concat(
        <tr key={week}>
  
        </tr>
      );
      return result;
    }
  }

  return(
    <div>
      <div>
        <button onClick={()=> {setMoment(getMoment.clone().subtract(1, 'month')) }}>이전달</button>
        <span>{today.format('YYYY년 MM월')}</span>
        <button onClick={()=> {setMoment(getMoment.clone().add(1, 'month')) }}>다음달</button>
      </div>
        <table>
          <tbody>
            {calenderArr()}
          </tbody>
        </table>
    </div>
  );
}

export default Calender;

 

 

 

이제 week가 설정됐으니 days를 설정해주면 된다.

week 수 만큼 7일 기준으로 반복문을 출력해주면 아래와 같이 출력된다.

 

<tr key={week}>
          {
            Array(7).fill(0).map((data, index) => {
              let days = today.clone().startOf('year').week(week).startOf('week').add(index, 'day');

              return(
                <td key={index}>
                  <span>{days.format('D')}</span>
                </td>
              );
            })
          }
</tr>

 

여기서 중요한 부분은 moment()는 현재 날짜를 기준으로 하기 때문에 startOf('year')가 없어도 될 것 같지만 필요하다.

위에서 설정한 53번째 주 같은 경우가 생기면 moment()는 1을 반환하기 때문에 53으로 바꿔주었는데 days에서 사용한 today 변수도 이런 문제가 생길 수 있기 때문에 연도를 꼭 지정해주는 게 필요하다.

 

 

 

3) 색깔 입히기

 

마지막으로 오늘에 해댕하면 현재 날짜인 moment().format을 사용해 오늘이 맞으면 배경색을 빨간색으로, 

그 달에 있는 날짜가 아니면 회색으로, 둘 다 아니라면 색이 없이 나오도록 설정했다.

 

<tr key={week}>
          {
            Array(7).fill(0).map((data, index) => {
              let days = today.clone().startOf('year').week(week).startOf('week').add(index, 'day');

              if(moment().format('YYYYMMDD') === days.format('YYYYMMDD')) {
                return (
                  <td key={index} style={{backgroundColor: 'red'}}>
                    <span>{days.format('D')}</span>
                  </td>
                );
              } else if(days.format('MM') !== today.format('MM')) {
                return (
                  <td key={index} style={{backgroundColor: 'gray'}}>
                    <span>{days.format('D')}</span>
                  </td>
                );
              } else {
                return (
                  <td key={index}>
                    <span>{days.format('D')}</span>
                  </td>
                );
              }
            })
          }
        </tr>

 

 

달력 만들기는 끝났고 이제 CSS만 적용하면 된다!

 

 

 

 

 

 

 

 

참고

https://momentjscom.readthedocs.io/en/latest/moment/04-displaying/01-format/

https://yeolceo.tistory.com/m/69

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함