[React] 라우터 - 고급기능

p-q·2023년 4월 10일
0

react

목록 보기
2/5

loader()

loader()

loader 프로퍼티는 특정 경로에 대한 컴포넌트를 로딩할 때 사용됩니다. 이를 통해 초기 번들의 크기를 줄이고 페이지 로드 속도를 향상시킬 수 있습니다.

loader 함수는 일반적으로 데이터를 가져오는 비동기 함수와 함께 사용됩니다. 이를 통해 데이터가 로드되는 동안 로딩 스피너 또는 로딩 메시지를 표시할 수 있습니다. 데이터가 로드되면 컴포넌트가 렌더링되어 사용자에게 표시됩니다.

const router = createBrowserRouter([
  {
    path: "/",
    element: <RootLayout />,
    children: [
      { index: true, element: <HomePage /> },
      {
        path: "events",
        element: <EventLayout />,
        children: [
          {
            index: true,
            element: <EventPage />,
            loader: eventsLoader,
          },
          { path: ":eventId", element: <EventDetailPage /> },
          { path: ":eventId/edit", element: <EditEventPage /> },
          { path: "new", element: <NewEventPage /> },
        ],
      },
    ],
  },
]);

동적으로 컴포넌트를 가져오고, 해당 모듈이 로드될 때까지 코드 실행을 일시 중지합니다. 모듈이 로드되면 해당 모듈에서 내보낸 컴포넌트를 반환합니다. 이를 통해 초기 번들의 크기를 줄이고 페이지 로드 속도를 향상시킬 수 있습니다.

loader 함수를 사용하여 컴포넌트를 비동기적으로 로드함으로써 초기 번들의 크기를 줄이고 페이지 로드 속도를 향상시킬 수 있습니다.

loader 데이터 컴포넌트에서 사용하기

useLoaderDate

useLoaderData 훅은 react-router-dom에서 제공하는 비동기 데이터 로딩을 위한 훅으로, loader 함수에서 반환한 데이터를 컴포넌트 내에서 사용할 수 있게 해줍니다.

아래의 코드는 useLoaderData 훅을 사용하여 loader 함수에서 반환한 데이터를 가져오고, 해당 데이터를 컴포넌트에서 사용하는 예시입니다.

javascript

import { useLoaderData, json } from "react-router-dom";

import EventsList from "../components/EventsList";

const EventsPage = () => {
  const response = useLoaderData();
  const events = response.events;
  
  return <>{<EventsList events={events} />}</>;
};

export default EventsPage;

export const loader = async () => {
  const response = await fetch("http://localhost:8080/events");
  if (!response.ok) {
    throw json({ message: "Could not fetch events." }, { status: response.status});
  } else {
    return response;
  }
};

위의 코드에서 EventsPage 컴포넌트에서 useLoaderData 훅을 사용하여 loader 함수에서 반환한 response 데이터를 가져옵니다. 이를 통해 events 배열을 추출하고, 해당 배열을 EventsList 컴포넌트에 전달하여 렌더링합니다.

이렇게 컴포넌트 내에서 필요한 데이터를 로드하여 불필요한 데이터를 렌더링하지 않음으로써 성능을 향상시킬 수 있습니다. 따라서, 권장되는 방향은 해당하는 컴포넌트에 loader를 넣는 것입니다.

loader 함수가 실행되는 시기

loader 함수가 실행되는 시기는 해당하는 페이지로 이동하기 전에 실행되며, 이를 통해 페이지 이동 속도를 빠르게 할 수 있습니다.

네비게이션 상태 UI 반영하기

useNavigation

현재 화면의 네비게이션 상태를 확인할 수 있습니다. 이를 통해 현재 화면이 어떤 화면인지, 어떤 파라미터를 가지고 있는지 등을 알 수 있습니다. 이 정보를 활용하여 UI를 업데이트하거나 다른 작업을 수행할 수 있습니다. 예를 들어, 현재 화면이 로딩 중인지 여부를 파악하여 로딩 상태를 UI에 반영하는 등의 작업에 활용할 수 있습니다.
import React from 'react';
import { Outlet, useNavigation } from 'react-router-dom';
import MainNavigation from '../components/MainNavigation';

const RootLayout = () => {

  const navigation = useNavigation();


  
  return (
    <>
      <MainNavigation />
      <main>
        {navigation.state === 'Loading' && <p>Loading...</p>}
        <Outlet />
      </main>
    </>
  );
};

export default RootLayout;

로딩 상태를 추가할 때는 해당 컴포넌트가 아닌 이미 렌더링된 상위 컴포넌트에 추가해야 합니다. 이렇게 함으로써, 로딩 상태가 발생하면 이미 렌더링된 상위 컴포넌트가 업데이트되고, Outlet을 렌더링하는 모든 하위 컴포넌트에 로딩 상태가 전파됩니다. 이것은 React의 단방향 데이터 흐름 모델과 일치하며, 불필요한 렌더링을 방지하여 애플리케이션의 성능을 향상시킵니다.

loader 에서 응답 리턴하기

다음은 "loader에서 응답 반환하기"에 대한 예제입니다.

const router = createBrowserRouter([
  {
    path: "/",
    element: <RootLayout />,
    errorElement: <ErrorPage/>,
    children: [
      { index: true, element: <HomePage /> },
      {
        path: "events",
        element: <EventLayout />,
        children: [
          {
            index: true,
            element: <EventPage />,
            loader: eventsLoader,
          },
          { path: ":eventId", element: <EventDetailPage /> },
          { path: ":eventId/edit", element: <EditEventPage /> },
          { path: "new", element: <NewEventPage /> },
        ],
      },
    ],
  },
]);

위 코드는 createBrowserRouter 함수를 사용하여 브라우저 라우팅을 설정하는 예제입니다. 해당 코드에서는 /events 경로에 대한 라우트를 정의하고, 이벤트 페이지를 로딩할 때 eventsLoader 함수를 호출합니다. 이 함수는 Promise 객체를 반환하며, 로딩 중인 동안 표시할 UI를 렌더링합니다. 로딩이 완료되면, 이 함수에서 반환한 Promise 객체에 따라 적절한 응답을 반환합니다. 이 예제를 참고하여, 로딩 중에도 적절한 응답을 반환하는 라우트를 만들 수 있습니다.

custom error 를 이용한 오류처리

export const loader = async () => {
  const response = await fetch("http://localhost:8080/events");
  if (!response.ok) {
    return {isError: true, message: "Something went wrong!"}
  } else {
    return response;
  }
}

export const loader = async () => {
  const response = await fetch("http://localhost:8080/events");
  if (!response.ok) {
    throw new Error('Something went wrong');
  } else {
    return response;
  }
}

위 코드는 custom error를 이용한 오류 처리에 대한 예제입니다.

첫 번째 방법은, 오류 객체를 반환하여 컴포넌트에서 이를 처리하는 것입니다. 위 코드에서는, 응답이 실패한 경우 {isError: true, message: "Something went wrong!"} 객체를 반환하여 오류가 발생했음을 알리고, 컴포넌트에서 이를 처리할 수 있도록 합니다.

두 번째 방법은, throw new Error() 구문을 사용하여 에러 객체를 던지는 것입니다. 이 경우, 브라우저 콘솔에 오류 메시지가 출력됩니다. 이 방법은 오류 발생 시 즉시 처리가 필요한 경우에 적합합니다.

이렇게 custom error를 이용하여 오류 처리를 하는 것은, 프로그램의 안정성과 유지보수성을 높일 수 있습니다.

오류 데이터 추출하고 응답 내보내기

export const loader = async () => {
  const response = await fetch("http://localhost:8080/evesnts");
  if (!response.ok) {
    throw new Response(JSON.stringify({ message: "Could not fetch events." }), { status: response.status });
  } else {
    return response;
  }
};

먼저, loader 함수에서는 fetch() 함수를 사용하여 "http://localhost:8080/events" 경로로부터 데이터를 가져옵니다. 응답이 성공적이지 않은 경우, Response 객체를 던지는데 이 객체는 응답에 대한 정보를 가지고 있습니다. 이 객체를 브라우저에게 반환함으로써, 응답이 실패한 이유를 알리고 오류에 대한 정보를 전달할 수 있습니다.

import classes from './PageContent.module.css';

const PageContent = ({ title, children }) => {
  return (
    <div className={classes.content}>
      <h1>{title}</h1>
      {children}
    </div>
  );
}

export default PageContent;
import React from "react";
import PageContent from "../components/PageContent";
import { useRouteError } from "react-router-dom";
import MainNavigation from "../components/MainNavigation";

const ErrorPage = () => {
  const error = useRouteError();

  let title = "An error occurred!";
  let message = "Something went wrong.";

  const errorData = JSON.parse(error.data);

  if (error.status === 500) {
    message = errorData.message;
  }

  if (error.status === 404) {
    title = "Page not found!";
    message = "The page you are looking for does not exist.";
  }

  return (
    <>
      <MainNavigation />
      <PageContent title={title}>
        <p>{message}</p>
      </PageContent>
    </>
  );
};

export default ErrorPage;

다음으로, ErrorPage 컴포넌트에서는 useRouteError() 훅을 사용하여, 라우팅 중에 발생한 오류에 대한 정보를 가져옵니다. 이 정보는 JSON.parse() 함수를 사용하여 추출합니다. 이후, 오류 상태 코드에 따라 적절한 오류 메시지를 표시하고, PageContent 컴포넌트를 사용하여 오류 메시지를 UI에 표시합니다.

이렇게, 오류 데이터를 추출하고 응답을 내보내는 것은, 프로그램의 안정성과 유지보수성을 높일 수 있습니다. 또한, 사용자가 오류 상황에서도 적절한 오류 메시지를 볼 수 있도록 해줍니다.

profile
ppppqqqq

0개의 댓글