반응형

useQuery 옵션 중에 onSuccess, onError, onSettled 같은 상태 변화가 일어날 때 트리거해주는 옵션이 있다.

 

 

현재 조회하고 있는 데이터의 상태에 따라 동작을 수행할 수 있어 onSuccess 에서 state 를 변경하곤 한다.

심지어 구글 첫 번째 검색 결과인 스택오버플로우에서도 권장하고 있는 방법이었다.

 

javascript - Store data from useQuery with useState - Stack Overflow

 

Store data from useQuery with useState

I'm using React hooks both to fetch GraphQL data with react-apollo and to store local state: const [userData, setUserData] = useState({}) const { loading, error, data } = useQuery(USER_QUERY) How...

stackoverflow.com

 

하지만 이는 안티패턴이라고 한다. Suspense 같은 React 에서 지원하는 컴포넌트를 같이 사용하게 될 때 렌더링 순서가 어떻게 바뀔지 모르기 때문이다. 

 

setState in onSuccess is not working first time with suspense · Issue #3784 · TanStack/query (github.com)

 

setState in onSuccess is not working first time with suspense · Issue #3784 · TanStack/query

Describe the bug With Suspense, calling setState in useQuery.onSuccess is not changing state. I found that this issue would be fix turning off refetchOnWindowFocus. but it still no good UX (require...

github.com

 

실제로 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 로 모니터링하고 해당 결과 값이 바뀌면 상태를 바꾸어야 한다.

반응형

+ Recent posts