JS
React Router의 loader 사용기
heavy-bear
2024. 12. 3. 23:16
리액트 라우터의 loader 함수를 통해서 fetch thenrender와 render as you fetch를 섞어보려고 한 시도에서 겪은 이슈들을 정리해 보았습니다.
데이터 패칭 전략 3가지
- Fetch-on-render
- 컴포넌트가 마운트 된 후에 데이터 패칭을 시작합니다.
- 가장 일반적인 방식으로 컴포넌트 렌더링후 useEffect등을 사용해 데이터를 가져옵니다.
- 여러 비동기 요청이 순차적으로 실행될 수 있어 '워터폴' 문제 발생 가능성이 있습니다.
- Fetch-then-render
- 데이터를 먼저 가져온 후 컴포넌트를 렌더링합니다.
- 데이터가 준비된 상태에서 랜더링하므로, 컴포넌트에 별도 로딩과 관련된 부분을 작성하지 않아도 됩니다.
- 하지만 데이터가 로드될때까지 렌더링이 지연될 수 있습니다.
- Render-as-you-fetch
- 화면을 먼저 렌더링 하고 데이터를 받아오면 화면을 동적으로 업데이트합니다.
- 전체적인 로딩 시간을 단축 하고 워터폴 문제를 해결 할 수 있습니다.
React Router의 loader로 두 가지 전략을 섞어서 표현하기
- 핵심 데이터(필수적인 데이터)는 await을 사용하여 렌더링 전에 로드하고 (fetch then render)
- 천천히 받아도 될 데이터는 즉시 반환하고 렌더링시 suspense를 이용해 fallback ui 표현 (render as you fetch)
async function loader({ params }) {
const { id } = params;
const detail = getProduct(id);
const comments = getProductComments({ productId: id, limit: 5 });
return { detail: await detail, comments };
}
export default function ItemDetailPage() {
const { detail, comments } = useLoaderData();
return (
<PageWrapper>
{/* critical */}
<ProductDetail detail={detail} />
{/* non critical */}
<Suspense fallback={<Loading>상품 문의를 가져오는 중입니다....</Loading>}>
<Await resolve={comments}>
{(comments) => <CommentList comments={comments} />}
</Await>
</Suspense>
</PageWrapper>
);
}
로딩 UI 처리 방법
- react의 Suspense와 react-router의 Await을 사용하여 데이터를 기다리는 동안 로딩 UI를 표시할 수 있습니다.
- Suspense 컴포넌트는 로딩 상태 동안 fallback UI를 보여주며, 데이터가 로드되면 그 데이터를 기반으로 페이지가 렌더링 됩니다.
상품정보 자체를 로딩할 때는 로딩 상태를 표현할 수 없는가?
- 테스트로 임의로 상품정보 데이터 로딩에 지연을 줬을 때, 화면이 멈춘 것처럼 가만히 있다가 이동을 합니다.
- loader가 페이지를 이동 전에 필요한 데이터를 꼭 받아야 하므로 일어나는 현상입니다. (loader 실행순서!!)
- 이럴 때는 loader가 속한 라우팅의 상위 레벨의 컴포넌트에서 useNavigation의 state의 상태가 loading임을 체크해서 데이터 로딩 중을 보여주면 됩니다.
왜 새로고침이나 url로 직접 접근을 하면 왜 하안색 빈 화면만 나올까?
- 앱이 실행되고 react router가 실행되면서, 컴포넌트가 랜더링 되기 전에 loader가 실행되어서 발생하는 빈화면입니다.
- 이때 HydrateFallbackElement에 로딩 컴포넌트를 넣어주게 되면 데이터가 준비될 때까지 로딩 UI를 보여 줄 수 있습니다.
- HydrateFallback은 SSR(서버 사이드 렌더링)과 CSR(클라이언트 사이드 렌더링) 초기화 과정에서만 사용됩니다. React 앱이 이미 초기화되면 HydrateFallback은 사용되지 않으며, 대신 useNavigation을 통해 로딩 상태를 표시할 수 있습니다.
- https://reactrouter.com/upgrading/v6#v7_partialhydration
Upgrading from v6 | React Router
reactrouter.com