본문으로 바로가기
TaeyoungKim.dev

React Router loader로 데이터 로딩하기: 화면 렌더링 전 오류를 다루는 방법

웹작성 약 3분 읽기TaeyoungKim
LinkedInX

컴포넌트가 렌더링된 뒤 useEffect에서 데이터를 가져오면 로딩·오류·이전 화면 요청을 각 컴포넌트가 따로 해결하게 된다. React Router의 Data Mode에서는 route의 loader를 데이터 진입점으로 둘 수 있다.

loader는 라우트 진입 전에 데이터를 요청한다

도식은 라우트 진입 시 loader가 먼저 데이터를 요청하고, 성공 결과와 오류가 서로 다른 렌더링 경계로 전달되는 흐름을 보여 준다. 사용자 한 명을 읽는 라우트로 연결해 보자.

jsx
import {
  createBrowserRouter,
  RouterProvider,
  useLoaderData,
  useRouteError,
} from "react-router";

function PostPage() {
  const post = useLoaderData();
  return <h1>{post.title}</h1>;
}

function RouteError() {
  const error = useRouteError();
  return <p>{error?.status === 404 ? "글이 없습니다" : "다시 시도해 주세요"}</p>;
}

const router = createBrowserRouter([
  {
    path: "/posts/:postId",
    element: <PostPage />,
    loader: async ({ params, request }) => {
      if (params.postId !== "1") {
        throw new Response("Not found", { status: 404 });
      }
      const demoUrl = "data:application/json," +
        encodeURIComponent(JSON.stringify({ title: "첫 글" }));
      const response = await fetch(demoUrl, { signal: request.signal });
      return response.json();
    },
    errorElement: <RouteError />,
  },
]);

export default function App() {
  return <RouterProvider router={router} />;
}

/posts/1은 제목을, /posts/2는 오류 화면을 보여 준다. 예제의 data: URL은 서버 없이 fetch 흐름을 보여 주기 위한 합성 응답이다. 실제 API로 바꿀 때는 response.ok를 검사해 실패 상태를 던져야 한다. 컴포넌트는 useLoaderData()로 성공 결과만 읽는다. 서버 요청에는 loader의 request.signal을 전달해 페이지 이동 시 불필요한 요청을 취소할 수 있다.

오류는 각 화면의 에러 경계에서 보여 준다

404와 서버 오류를 빈 배열이나 null로 숨기면 사용자와 개발자 모두 원인을 알기 어렵다. loader에서 상태에 맞는 오류를 던지고 errorElement에서 안전한 메시지와 다시 시도할 경로를 제공하자. 서버가 보낸 내부 오류 전문이나 민감한 정보를 그대로 출력하면 안 된다.

새로고침으로 경로에 직접 들어갔을 때 404가 난다면 loader보다 서버의 SPA 경로 재작성 설정을 먼저 확인한다. 반대로 페이지는 열리지만 오류 경계가 뜬다면 loader가 던진 상태와 브라우저 네트워크 응답을 대조한다.

loader가 모든 상태를 대신하지는 않는다

사용자 입력에 따라 즉시 바뀌는 필터, 모달의 임시 상태처럼 페이지 전역 데이터가 아닌 값은 컴포넌트 상태가 더 자연스럽다. loader에는 URL과 라우트 진입에 필요한 데이터를 두고, 서버 변경 작업은 action이나 명확한 API 호출로 분리하면 흐름을 따라가기 쉽다.

loader의 세 응답을 구분한다

기존 /posts/:postId 라우트에서 API가 정상 JSON, 404, 500을 돌려주는 경우를 각각 테스트한다. 정상 응답은 useLoaderData()로 읽히고 오류 응답은 errorElement로 이동해야 한다. 404와 500을 모두 'Not found'로 표시하면 운영 진단과 사용자 안내가 어긋난다.

js
async function readPostResponse(response) {
  if (response.status === 404) throw new Response("글 없음", { status: 404 });
  if (!response.ok) throw new Response("불러오기 실패", { status: response.status });
  return response.json();
}

서버가 보낸 오류 본문을 그대로 노출하지 않고, 라우트 이동 중 이전 요청이 취소되는지도 확인한다. 읽기 권한은 loader만 믿지 말고 서버에서도 검사해야 한다.

핵심 요약

loader는 라우트 진입 시 필요한 데이터를 컴포넌트보다 먼저 준비하고, 라우터의 요청 취소·오류 경계와 연결한다. 성공·404·서버 오류를 명시적으로 나누고, 화면 내 임시 상태까지 loader로 몰아넣지 말자. 데이터의 수명과 URL의 관계를 기준으로 경계를 정하면 코드가 단순해진다.

작성자

TaeyoungKim

기초 개념을 구현과 검증, 실제 운영 판단까지 연결해 기록합니다.

#React#React Router#loader#데이터 로딩#에러 처리

함께 읽으면 좋은 글