React - React Query 와 setState

Einere·2022년 8월 30일
4
post-thumbnail

1. 발단

마켓 플레이스의 정산쪽을 개발하면서, 새로운 기술을 많이 적용했다. 그 중의 하나가 React Query인데, 이녀석을 사용하면서 굉장히 난감한 상황을 마주치게 되었다.

[실제 영상은 대외비라, 코드 샌드박스 예제로 대체하였습니다.]

코드는 간략하게 다음과 같다.

function SalesOfCustomerManagement(props: SalesOfCustomerManagementProp) {
  const [selectedYear, setSelectedYear] = useState(dayjs());
  const [salesList, setSalesList] = useState<Sales[]>([]);

  const { refetch } = useQuery(
    [QUERY_KEY.API_CUSTOMER_SALES, customerId, selectedYear.year()],
    () => profitAPI.getSalesOfCustomer(customerId, selectedYear.year()),
    {
      refetchOnWindowFocus: false,
      onSuccess: (data) => {
        setInitialSalesList(data.customerSalesList);
        setSalesList(data.customerSalesList);
      },
    }
  );
  // ...
}

코드를 보면 딱히 이상한 점은 찾을 수 없었다.

그래서 React Query 깃헙 레포에다가 이슈를 하나 올렸다.

2. 해결 방법

해당 이슈에 달린 댓글을 보면, 해결 방법을 가르쳐주신 분이 계셨다.

If you really want to sync state, prefer an effect…

즉, 상태를 동기화 하고 싶다면 useEffect 를 쓰라는 것이었다.

[실제 영상은 대외비라, 예시 영상은 제거하였습니다.]

오! 잘 된다.

그렇다면 무슨 차이가 있는 것일까?

3. 원인

이 또한 해당 스레드에 잘 나와 있는데, 다음과 같다.

SuspenseuseQuery , useEffect 가 동작하는 방식

  1. <Suspense> 컴포넌트가 마운트 된다.
  2. 자식 컴포넌트가 마운트 된다.
  3. 비동기 함수가 호출이 된다. (e.g. useQuery)
  4. <Suspense> 컴포넌트가 자식의 비동기 함수를 관찰하고, 자식 컴포넌트를 언마운트한다. 그리고 폴백 컴포넌트를 마운트한다.
  5. 이 시점에, useEffect 는 불리지 않는다. 왜냐하면 이미 언마운트 되었기 때문이다.
  6. 비동기 함수가 특정 결과를 반환했을 때 (e.g. data), 해당 결과는 캐싱되며, <Suspense> 는 폴백 컴포넌트를 언마운트하고 자식 컴포넌트를 마운트한다.
  7. 이 시점에, useEffect 가 호출되고, useQuery 는 캐시에 저장되어 있던  data 를 가져온다. 따라서 유저는 매끄러운 화면을 볼 수 있다.

SuspenseuseQuery , onSuccess 가 동작하는 방식

  1. <Suspense> 컴포넌트가 마운트 된다.
  2. 자식 컴포넌트가 마운트 된다.
  3. useQuery 는 Proimse를 던진다.
  4. Promise의 상태가 pending 상태이므로 <Suspense> 컴포넌트가 자식 컴포넌트를 언마운트한다. 그리고 폴백 컴포넌트를 마운트한다.
  5. 비동기 함수가 특정 결과를 반환했을 때 (e.g. data), 해당 결과는 캐싱되며, onSuccess 가 호출된다.
  6. 이 시점에, 언마운트된 자식 컴포넌트의 상태를 갱신하려고 하기 때문에 아무 일도 일어나지 않는다.
  7. 3번에서 던진 Proimse가 fulfilled 상태가 되면 폴백 컴포넌트가 언마운트되며, 자식 컴포넌트가 마운트된다.
  8. 자식 컴포넌트의 상태는 기본 값으로 초기화된다.

4. 참고

GitHub - setState in onSuccess is not working first time with suspense

5. 덧

동료분의 분노의 리뷰...

[동료분의 분노의 리뷰...]

profile
지속가능한 웹 개발자를 지향합니다. 경험의 공유를 통해 타인에게 도움이 되는 것을 좋아합니다. 사용자에게 가치를 제공하는 것에 기쁨을 느낍니다.

0개의 댓글