캘린더 앱을 만들고자 직접 달력을 구현해보려고 한다
달력을 만들기 위해 필요한 날짜를 얻어오기 위해
npm i date-fns
https://www.npmjs.com/package/date-fns
https://date-fns.org/v2.28.0/docs/Getting-Started
내가 사용한 방식은 아래와 같다
1. 오늘 날짜를 가져온다
const date = new Date();
2. 오늘 날짜를 통해 이번달을 얻어낸다
const curMonth = getMonth(date);
3. 오늘 날짜를 통해 이번달을 1일을 알아낸다
const monthStart = startOfMonth(data);
이제 이번달의 1일을 알고있으니, 방법은 2가지
이번달을 첫번째주부터 마지막주까지 알아내느냐와 단순히 1일부터 말일까지를 알아내는냐이다
(두개의 결과가 조금 다르다)
일단 첫번째 첫주부터 마지막주까지 알아내는 방법
1. 1일 기준으로 이번달이 몇주인지 알아낸다
const weekLength = getWeeksInMonth(monthStart);
2. 1일을 기준으로 주의 시작 일자를 얻어낸다
data = monthStart;
const weekStart = startOfWeek(data, {weekStartOn:0});
이때 weekStartOn 옵션으로 주의 시작이 무슨요일일지 정한다 ( 0부터시작, 일요일부터 시작 )
3. 주의 첫번째 일자를 기준으로 7일을 얻어낸다 ( 7일씩 주수만큼 반복해 얻어내면 한달이 된다)
주의 첫번째일자를 기준으로 1부터 6까지 하나씩 더해가면 일주일의 날짜를 얻어낸다
formatted은 요일, day는 일자, month는 이번달인지 지난달인지 다음달인지 구분
const weekLength = 7;
for(let i =0;i<weekLength;i++){
const tempDate = addDays(weekStart,i);
if(getMonth(tempDate) === month){
weekList.push({
formatted,
date : tempDate,
day : getDate(tempDate),
month: 'cur'
})
}else if(getMonth(tempDate) < month){
weekList.push({
formatted,
date : tempDate,
day : getDate(tempDate),
month:'pre'
})
}else if(getMonth(tempDate) > month){
weekList.push({
formatted,
date : tempDate,
day : getDate(tempDate),
month: 'next'
})
}
해당 결과를 통해 화면에 출력해보면 아래와 같은 결과를 얻을수 있다.
이번달이아닌 지난달과 다음달을 날짜는 색상을 다르게해 구분을 둘수 있다.
두번째로 1일부터 말일까지의 날짜를 얻어내는 방법은
1. 현재달이 몇일인지를 얻어낸다
const monthLength = getDaysInMonth(date);
2. 1일부터 마지막일까지 1씩 더해가면서 날짜를 얻어낸다.
for(let i =0;i<monthLength;i++){
const tempDate = addDays(monthStart,i);
if(getMonth(tempDate) === month){
weekList.push({
formatted,
date : tempDate,
day : getDate(tempDate),
})
}
달력을 구현했으니 이제 다음달 이전달을 구해보자
현재 월 시작일기준(1일)다음달인지 이전달인지에 따라 기준 날짜를 구한뒤 위에 구한 방법으로 한달의 날짜를 구해낸다
const nextDate = addMonths(monthStart, 1); 다음달
const preDate = addMonths(monthStart, -1); 이전달
코드정리
const date = new Date(); //오늘날짜를 생성
const today = getDate(date);//날짜를 가져온다
const curMonth = getMonth(date);//오늘날짜를 기준으로 현재달을 구한다
const monthDays = this.getMonthDays(date, curMonth);//오늘날짜와 현재달을 갖고 한달의 날짜를 구한다
//한달구하기
getMonthDays(data, month){
const monthStart = startOfMonth(data); //달 시작일 구하기 --> 1일
const monthList = [];
const weekLength = getWeeksInMonth(monthStart); --> 기준달이 몇주인지 구하기
this.setState({
weekLength,
calendarDay:monthStart,
})
for(let i=0;i<weekLength;i++){
const count = i*7;
const weekStartDate = addDays(monthStart, count)
monthList.push(this.getWeekDays(weekStartDate, month));
}
return monthList;
}
//한주 구하기
getWeekDays(data, month){
const weekStart = startOfWeek(data, {weekStartOn:1});//기준날짜를 통해 주 시작일 구하기
const weekLength = 7;
const weekList = [];
for(let i =0;i<weekLength;i++){
const tempDate = addDays(weekStart,i);
const formatted = this.getDay(format(tempDate,'EEE'));
if(getMonth(tempDate) === month){
weekList.push({
key: getDate(tempDate),
formatted,
date : tempDate,
day : getDate(tempDate),
month: 'cur'
})
}else if(getMonth(tempDate) < month){
weekList.push({
key: getDate(tempDate),
formatted,
date : tempDate,
day : getDate(tempDate),
month:'pre'
})
}else if(getMonth(tempDate) > month){
weekList.push({
key: getDate(tempDate),
formatted,
date : tempDate,
day : getDate(tempDate),
month: 'next'
})
}
}
return weekList;
}
//요일 표시법바꾸기
getDay(day){
var dayWord = day;
if(dayWord === 'Sun'){
dayWord='일';
}else if (dayWord === 'Mon'){
dayWord='월';
}else if (dayWord === 'Tue'){
dayWord='화';
}else if (dayWord === 'Wed'){
dayWord='수';
}else if (dayWord === 'Thu'){
dayWord='목';
}else if (dayWord === 'Fri'){
dayWord='금';
}else if (dayWord === 'Sat'){
dayWord='토';
}
return dayWord;
}
//다음달구하기
getNextMonth(){
const nextDate = addMonths(this.state.monthStart, this.state.nextCount + 1);
const month = getMonth(nextDate);
const nextMonth = this.getMonthDays(nextDate, month);
this.setState({
nextCount:this.state.nextCount+1,
monthDays:nextMonth,
curMonth:month,
})
}
//이전달 구하기
getPreMonth(){
const preDate = addMonths(this.state.monthStart, this.state.nextCount - 1);
const month = getMonth(preDate);
console.log(preDate)
const preMonth = this.getMonthDays(preDate, month);
this.setState({
nextCount:this.state.nextCount-1,
monthDays:preMonth,
curMonth:month,
})
}
화면표기
<View style={style.calendar}>
{this.state.monthDays ? this.state.monthDays.map((el,index)=>{
return(
el.map((sub,index)=>{
return(
<View style={[style.dayView, this.state.weekLength === 4 ? style.week4 : this.state.weekLength === 5 ? style.week5 : this.state.weekLength === 6 ? style.week6 : null]} key={index.toString()}>
<Text style={[style.dayText, sub.month !== 'cur' ? style.dayText2 : null]}>{sub.day} {sub.formatted}</Text>
</View>
)
})
)
}): null}
</View>
4주인지 5주인지 6주인지에 따라 높이 변화가 필요함.
dayView:{
width: wp('14.3%'),
},
week4:{
height:hp('23%'),
},
week5:{
height: hp('18%')
},
week6:{
height: hp('14%'),
},
참고자료
wp, hp를 모른다면 ?
[리액트네이티브] - [react-native] 컴포넌트의 크기를 지정할때 화면비율에 맞게 지정하는 간단한 방법
'리액트네이티브 > 앱만들기기록' 카테고리의 다른 글
1 - RN 초기화 (1064) | 2022.01.19 |
---|
댓글