URI창과 달력 인풋 값을 고려해야 했다.
이미 한번 리팩토링을 했던 코드였는데, 이 때는 checkin, checkout을 키로 바로 쿼리스트링을 넣어주었었다.
이제는 dates를 키로 dates=checkin='2022-04-23'&checkout=...
의 형태로 넣어야 하므로 다른 로직이 필요했다.
const checkinDate = URLSearch.get('checkin');
const checkoutDate = URLSearch.get('checkout');
const handleDatesChange = ({ startDate, endDate }) => {
setStartDate(startDate);
setEndDate(endDate);
};
useEffect(() => {
startDate && URLSearch.set('checkin', startDate.format('YYYY-MM-DD'));
endDate && URLSearch.set('checkout', endDate.format('YYYY-MM-DD'));
navigate(`/list?` + URLSearch.toString());
}, [focusedInput]);
그런데 의외의 제약 사항이 있었다.
이 달력 라이브러리는 다음과 같은 원리로 작동된다.
달력을 클릭할 때마다 focusedInput이라는 prop이 각각 startDate, endDate, null로 변경된다. 처음 startDate일 때 달력 중 한 날짜를 클릭하면 예약 시작 날짜로 선택되며, endDate일 때 선택한 날짜는 예약 마지막 날짜가 되어 예약 구간이 표시된다. null일 때 달력이 사라진다.
각각 시작날짜와 끝날짜는 startDate와 endDate에 업데이트 된다.
그런데 한번에 객체 항목으로 넣게 되면 하나는 null로 업데이트 되기 때문에... 따로 따로 관리해야 했다.
제대로 동기화가 되지 않았던 문제
URI 변경시마다
useQueryStringObject에서 관리하는 상탯값에 업데이트를 하고, url창이 변경될 때마다
url창의 주소가 변경될 때마다 dates 키의 값으로 들어간 쿼리스트링 값을 객체로 변환하여 상탯값으로 업데이트 한다.
이 상탯값에 따라 url창, 달력의 인풋창과 선택값이 업데이트 된다.
const URLSearch = new URLSearchParams(location.search)
const dates = URLSearch.get('dates')
useEffect(() => {
const newDates = parseQueryIntoObject(dates);
setSelectedListObject(newDates);
}, [location.search]);
달력의 focusedInput이 바뀔 때마다 실행하는 함수 prop인 onFocusChange에 handleDatesChange함수를 전달해주었다. 달력에서 날짜를 선택할 때마다 달력 인풋창에 입력되는 값이 표시되도록 startDate, endDate 상탯값을 업데이트 해주었다.
const handleDatesChange = ({ startDate, endDate }) => {
startDate &&
setSelectedListObject({
...selectedListObject,
checkin: startDate.format('YYYY-MM-DD').toString(),
});
endDate &&
setSelectedListObject({
...selectedListObject,
checkout: endDate.format('YYYY-MM-DD').toString(),
});
setStartDate(startDate);
setEndDate(endDate);
};
react-dates는 moment객체로 값을 반환하기 때문에 날짜형태로 변환하기 위해서 format메서드를 사용해주었다. 하지만 값이 없을 경우 에러가 나기 때문에 각 각 값이 있을 때만 로직을 처리하기 위해 startDate, endDate && 연산자를 추가했다.
좋지 않은 부분은 각각 두개의 상탯값을 동시에 관리하게 되었다는 점이다.
그리고 검색페이지에서 달력을 클릭할 때마다 실시간으로 url창의 쿼리스트링도 업데이트되어야 하기 때문에, 달력 라이브러리에 prop으로 전달하는 focusedInput값이 바뀔 때마다 변경되는 상탯값을 쿼리스트링으로 변환해 url창에 입력하도록 만드렁ㅆ다.
useEffect(() => {
parseObjectToSearchParams();
}, [focusedInput]);
url창이 변화할 때마다 숙박 기간에 표시될 수 있도록 쿼리스트링을 객체로 바꾸어 값들을 넣어주었다.
useEffect(() => {
const newDates = parseQueryIntoObject(dates);
setStartDate(moment(newDates.checkin));
setEndDate(moment(newDates.checkout));
}, [location.search]);
그리고 달력에서 각 날짜를 선택할 때마다 이 객체에 선택된 날짜를 넣어주고, 동시에 쿼리스트링으로 바꾸어 url창을 업데이트 해주었다.
const handleDatesChange = ({ startDate, endDate }) => {
const queryString = URLSearch.get('dates');
const queryObject = parseQueryIntoObject(queryString);
if (startDate) {
queryObject.checkin = startDate.format('YYYY-MM-DD');
if (endDate) {
queryObject.checkout = endDate.format('YYYY-MM-DD');
}
parseObjectToSearchParams(queryObject);
setStartDate(startDate);
setEndDate(endDate);
}
다른 검색 항목의 경우 체크박스, 슬라이더와 같이 리렌더링해 화면에 업데이트된 사항을 표시해야 했지만, 숙박 기간을 선택하는 이 컴포넌트에서는 별도로 필요가 없었기에 위의 코드로도 충분히 작동했다.