useQuery + Date객체 사용에서 주의점

JSLEE·2024년 10월 10일
0

상황

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객체에서 특정 시간을 변경해서 값을 비교하고 싶다면,
위처럼 새로운 인스턴스를 생성한 뒤 값을 비교해야 한다.
그렇지 않으면 원본의 값도 변경하게 되기 때문이다.

profile
공부한 내용들을 정리하기 위해 사용하는 블로그입니다.

0개의 댓글