useQuery 훅을 사용하면서, 쿼리파라미터로 selectedDate
라는 Date 인스턴스를 사용했다.
const [selectedDate, setSelectedDate] = useState(new Date());
const { data: todos, isPending: todosPending } = useQuery<GetTodosRes[]>({
queryKey: ['getTodos', selectedDate], // 이 부분
queryFn: () => getTodos(dayjs(selectedDate).format('YYYY-MM-DD')) ?? [],
});
그리고, todosPending
의 여부에 따라 Loader 컴포넌트가 나타나도록 했고,
return (
<>
...
todosPending ? <Loader /> : <></>
...
</>
A라는 버튼을 클릭했을 때, 00시 00분 00초의 값으로 날짜만 비교하기 위해서
if(selectedDate.setHours(0,0,0,0) < new Date()){
...
}
이라는 코드가 포함된 상황이다.
A버튼을 누르면 todosPending이 생기면서 Loader가 잠깐 나타났다가 사라지는 불필요한 렌더링이 발생했다.
문제의 원인은, date 객체의 .setHours
메소드가 파괴적 함수였기 때문이었다.
1. selectedDate.setHours(0,0,0,0)
가 동작하면서 selectedDate 의 값을 변경
2. useQuery의 쿼리파라미터에 변화 발생 -> 새로운 쿼리키로 인식 -> 쿼리문이 다시 동작
3. 새로운 쿼리키에 대한 pending 발생 -> Loader 컴포넌트 동작
따라서, 해당 부분의 코드를 다음과 같이 변경하였다.
const selectedDateMidnight = new Date(selectedDate);
selectedDateMidnight.setHours(0,0,0,0);
if(selectedDateMidnight < new Date()){
...
}
date객체에서 특정 시간을 변경해서 값을 비교하고 싶다면,
위처럼 새로운 인스턴스를 생성한 뒤 값을 비교해야 한다.
그렇지 않으면 원본의 값도 변경하게 되기 때문이다.