[React] 체크인, 체크아웃 state 반영 및 useCallback

jiseong·2021년 10월 1일
0

T I Learned

목록 보기
88/291

object에서 key값이 존재하지 않는 경우

달력의 날짜 배열을 생성할 때, object 형식으로 만들어주었다.

ex) [{day: '21', beforeDay=false}, {day: '22', beforeDay=false}, ...]

그리고 각 월마다 시작하는 요일은 다르기 때문에 unshift 방식을 이용하여 빈 공간을 채워주었는데 이렇게 되면 undefined 값을 가지기 때문에 key값에 접근할 때 오류가 나게 되었다.

arr.unshift(...new Array(firstDay))

하지만 object 형식으로 빈 공간을 채워준다면 존재하지 않는 key값이더라도 undefined 값을 리턴하기 때문에 오류가 뜨지 않는다.

// 변경된 방식
arr.unshift(...new Array(firstDay).fill(0).map((v, i) => ({})));

체크인, 체크아웃

메인페이지 기준으로 체크인, 체크아웃을 할 수 있게 변경하였다.
이를 위해서는 다음과 같은 조건들이 필요했다.

1. 체크인 날짜가 공백(달력에 보이는 빈칸)일 때

해당 경우는 달력의 배열을 만들 때 day날짜는 공백으로 만들어놨기 때문에 쉽게 판단할 수 있었다.

// Calendar.js
<div
  data-dateformat={`${monthData.year}-${monthData.month}-${date.day}`}
  css={dateBtn({ date })}
  key={`${monthData.year} + ${i}`}
  onClick={e => handleDatePick(e.target, date.beforeDay)}
  >
  {date.day}
</div>
// CalendarContainer.js
const handleDatePick = (target, beforeDay) => {
  const pickedDate = target.dataset.dateformat.split('-');
  const day = pickedDate[2];
  if (day === 'undefined') return; // 공백인 칸
};

2. 체크인 날짜가 오늘날짜보다 이전일 때

해당 경우도 마찬가지로 이전 날짜에 대해서도 boolean 값으로 저장이 되어있어 판단할 수 있었다.

// Calendar.js
<div
  data-dateformat={`${monthData.year}-${monthData.month}-${date.day}`}
  css={dateBtn({ date })}
  key={`${monthData.year} + ${i}`}
  onClick={e => handleDatePick(e.target, date.beforeDay)}
  >
  {date.day}
</div>
// CalendarContainer.js
const handleDatePick = (target, beforeDay) => {
  /* 생략... */
  if (beforeDay) return; // 이전 날짜
};

3. 체크아웃이 체크인보다 먼저일 때

우선, 체크인 날짜를 설정해야 체크아웃이 될 수 있게 하였다.

체크아웃을 설정할 때 기존의 체크인은 timeStamp형식으로 저장되어있기 때문에 체크아웃을 할 날짜와 체크인의 날짜를 비교하여 앞서게 되면 그 날짜를 체크인 날짜로 변경하는 방식으로 해주었다.

const handleDatePick = (target, beforeDay) => {
  /* 생략... */
  const timeStamp = new Date(`${pickedDate[0]}-${padding(pickedDate[1])}-${padding(pickedDate[2])}`,
  );
 
  if (!checkInDay || timeStamp < checkInDay) {
    console.log('체크인 날짜 설정...');
    changeCheckInOutDay('checkIn', timeStamp);
  } else {
    console.log('체크아웃 날짜 설정...');
    changeCheckInOutDay('checkOut', timeStamp);
  }
};

위에서 사용된 const timeStamp = new Date('2021-10-01');은 아래와 같은 결과를 얻게 되며 Date객체의 메서드를 사용할 수 있기 때문에 timeStamp 형식으로 관리한다면 유용하게 쓸 수 있다.

useCallback

또 검색창에 장소를 검색할 때 느려진다...
확인해보니까 기존의 원인이였던 SingleCalendar 컴포넌트가 불필요한 리렌더링을 하고있었다.

이유는 리렌더링시마다 새로 생성되는 상위 컴포넌트의 함수때문이였다.

<Calendar
  leftMonth={leftMonth}
  rightMonth={rightMonth}
  setMonth={setMonth}
  handleDatePick={handleDatePick}
/>

위에서 새로 추가한 handleDatePick함수가 리렌더링시마다 새로 생성되었기 때문에 이 함수를 건네받는 하위 컴포넌트인 SingleCalendar 컴포넌트는 값이 변경되었다고 인식을 하여 불필요한 리렌더링을 하고 있었다.

그렇다면 이번에는 리렌더링시 불필요한 함수가 재생성되는것을 방지해야 하는데 이는 useCallback을 이용하면 된다.

useMemo는 값을 반환하는 반면 useCallback은 함수를 반환하기 때문에 함수를 재활용하는 목적으로써 useCallback를 사용했다.

const handleDatePick = useCallback(
  (target, beforeDay) => {
    const pickedDate = target.dataset.dateformat.split('-');
    const timeStamp = new Date(
      `${pickedDate[0]}-${padding(pickedDate[1])}-${padding(pickedDate[2])}`,
    );
    const day = pickedDate[2];

    if (beforeDay) return;
    if (day === 'undefined') return;

    if (!checkInDay || timeStamp < checkInDay) {
      console.log('체크인 날짜 설정 중');
      changeCheckInOutDay('checkIn', timeStamp);
    } else {
      console.log('체크아웃 날짜 설정 중');
      changeCheckInOutDay('checkOut', timeStamp);
    }
  },
  [checkInDay, checkOutDay],
);

여기서 useMemo와 동일하게 두번째 인자의 의존성 상태값을 주의하며 사용해야 하며 useCallback를 사용하고나니 원하는 결과를 얻을 수 있게 되었다.

0개의 댓글