useQuery 옵션 중에 onSuccess, onError, onSettled 같은 상태 변화가 일어날 때 트리거해주는 옵션이 있다.
현재 조회하고 있는 데이터의 상태에 따라 동작을 수행할 수 있어 onSuccess 에서 state 를 변경하곤 한다.
심지어 구글 첫 번째 검색 결과인 스택오버플로우에서도 권장하고 있는 방법이었다.
javascript - Store data from useQuery with useState - Stack Overflow
하지만 이는 안티패턴이라고 한다. Suspense 같은 React 에서 지원하는 컴포넌트를 같이 사용하게 될 때 렌더링 순서가 어떻게 바뀔지 모르기 때문이다.
실제로 Suspense 와 useQuery 의 onSuccess (setState 동작) 를 같이 사용할 때 state 값이 업데이트가 되지 않는 이유를 물어보는 Tanstack/Query Issue 이다. 정리해보면 다음과 같다.
Suspense 와 useQuery, useEffect, onSuccess 가 호출되는 순서
1. <Suspense> 컴포넌트가 마운트 된다.
2. 자식 컴포넌트가 마운트 된다.
3. useQuery 비동기 함수가 호출이 된다. (이 때 Promise 를 던진다)
4. (<Suspense> 컴포넌트가 자식의 비동기 함수를 관찰하기 시작한다.)
Promise 의 상태가 Pending 상태이므로 <Suspense> 컴포넌트의 자식 컴포넌트가 언마운트된다.
그리고 Fallback 컴포넌트를 마운트한다.
5. 해당 시점에 useEffect 는 호출되지 않는다. 이미 언마운트 되었기 때문이다.
그러나 onSuccess 는 이 시점에 호출되고 언마운트 된 컴포넌트의 state 를 변경하려고 시도하기 때문에 아무 일도 일어나지 않는다.
6. Promise 의 상태가 Complete 되면서 특정 결과를 반환할 때 캐싱 처리된다.
7. Fallback 은 언마운트 되고 다시 자식 컴포넌트를 마운트한다.
8. 자식 컴포넌트가 마운트 되는 시점에 useEffect 가 호출되고, useQuery 캐시에 저장되어 있던 결과를 로드한다.
Suspense 가 결과가 회신되기 전까지 자식 컴포넌트를 언마운트하기 때문에 onSuccess 의 호출시점이 언마운트 중에 호출 되었다면 상태가 업데이트 되지 않는다는 것이다.
그래서 useQuery 로 도출한 결과 값을 useEffect 로 모니터링하고 해당 결과 값이 바뀌면 상태를 바꾸어야 한다.
'언어 > React' 카테고리의 다른 글
[React] Hook 은 사실 Closure 이다. (1) | 2023.10.16 |
---|---|
[React] 리소스 지연 로딩 (IntersectionObserver API) (0) | 2023.10.15 |
[React] debounce 최적화 (0) | 2023.10.15 |
[React] Hook 사용 시 유의사항 (0) | 2022.12.30 |