티스토리 뷰
*피드백은 언제나 환영합니다🙌
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
'Toy Project > Time to focus' 카테고리의 다른 글
- Total
- Today
- Yesterday
- rest parameter
- GitHub
- 리액트
- 유사배열객체
- 비동기
- hydrationboundary
- 취업까지달린다
- react
- arguments
- 중급 프로젝트
- tanstackquery
- 동기
- javascript
- map
- Next.js
- innerhtml
- js
- 객체
- html
- 코드잇 스프린트
- 프론트엔드
- 제어 컴포넌트
- Target
- 코드잇스프린트
- currentTarget
- Git
- 배열
- 비제어 컴포넌트
- CSS
- 스프린트프론트엔드6기
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |