리엑트 Suspense 딥다이브

이 자료가 도움이 많이 되었음!

내가 이해한 동작 방식

대부분의 예시는 아래처럼 함수 위에 값을 선언해서 계속해서 호출되더라도 값이 날라가지 않도록 한 뒤에 data fetching이 끝나면 data에 값을 할당하고 data에 값이 할당되면 return 하는 식이었음

let data;
export function useFetchSuspense<T>({ fetcher, key }: Props<T>) {
 ...
}

근데 우리는 캐싱을 구현했으니까 fetch의 결과를 캐시하고 만약 캐시된 값이 있으면 반환하는 식으로 하면 되지 않을까 해서 구현을 해봤고 결론적으로는 성공!

우리 코드

export function useFetchSuspense<T>({ fetcher, key }: Props<T>) {
  const promise = useRef<Promise<ResponseProps<any>>>();
  const { getCache, setCache } = useCache();
  const value = getCache({ key }) || { status: 'new', data: null, dataUpdatedAt: new Date() };

  if (value.status === 'rejected') {
    throw new Error(value.status);
  }
  if (value.status === 'resolved') {
    return value.data as T;
  }

  function fetchData() {
    promise.current = (async () => {
      return fetcher();
    })();

    promise.current
      .then(response => {
        setCache({
          key,
          value: {
            status: 'resolved',
            data: response.data,
            dataUpdatedAt: new Date(),
          },
        });
      })
      .catch(error => {
        setCache({
          key,
          value: {
            status: 'rejected',
            data: null,
            dataUpdatedAt: new Date(),
          },
        });
        throw new Error(error);
      });

    throw promise.current;
  }

  fetchData();

  throw promise.current;
}

사용 예시

이렇게 layout 단에서 크게 suspense로 묶으면 선언적으로 전체 fetching에 대한 로딩을 한번에 선언해 줄수도 있고

MyCarLayout.tsx

Untitled