본문 바로가기
리액트네이티브/앱만들기기록

2. RN 달력만들기(직접구현하기)

by 알찬 퍼블리셔 2022. 1. 27.
728x90
반응형

캘린더 앱을 만들고자 직접 달력을 구현해보려고 한다 

 

 

달력을 만들기 위해 필요한 날짜를 얻어오기 위해 

 

npm i date-fns

 

https://www.npmjs.com/package/date-fns

 

date-fns

Modern JavaScript date utility library

www.npmjs.com

https://date-fns.org/v2.28.0/docs/Getting-Started

 

Modern JavaScript Date Utility Library

date-fns provides the most comprehensive yet simple and consistent toolset for manipulating JavaScript dates in a browser & Node.js.

date-fns.org

 

 

 

내가 사용한 방식은 아래와 같다 

 

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%'),
    },

 

 

참고자료

Calendar.zip
0.00MB

 

 

wp, hp를 모른다면 ?

[리액트네이티브] - [react-native] 컴포넌트의 크기를 지정할때 화면비율에 맞게 지정하는 간단한 방법

728x90
반응형

'리액트네이티브 > 앱만들기기록' 카테고리의 다른 글

1 - RN 초기화  (1064) 2022.01.19

댓글