패스트캠퍼스 데브캠프

토이 3 프로젝트 - 작성한 코드 복기 (3)- Router 설정

vitamin3000 2025. 1. 19. 21:24

 

이번 포스트에서는 토이3 프로젝트에서 진행한 Router 설정에 대해 작성해보고자 한다.

 

우선, Router에는 각 페이지의 특성과 일치하는 URL과 컴포넌트가 존재할 것이다.

 

이러한 URL과 컴포넌트를src/constants/constant.ts에 작성한다.

 

1. Constant.ts

const ROUTER_PATH = {
  SPLASH: '/',
  HOME: '/home',
  LOGIN: '/login',
  PLAYLIST_DETAIL: '/playlist/:playlistId',
  KAKAO_REDIRECT: '/oauth/kakao',
  GOOGLE_REDIRECT: '/oauth/google',
};

const NAVIGATION_BAR = {
  HOME: 'HOME',
  PLAYLIST: 'PLAYLIST',
  BOOKMARK: 'BOOKMARK',
  MY_PAGE: 'MYPAGE',
};

const YOUTUBE_REGEX = {
  URL: /(?<=v=)([^?]+)?/g,
  SHORT_URL: /(?<=youtu\.be\/)([^?]+)?/g,
};

const PAGE_SIZE = 10;

export { ROUTER_PATH, NAVIGATION_BAR, YOUTUBE_REGEX, PAGE_SIZE };

 

이때 PLAYLIST_DETAIL과 같이, URL에 :playlistId가 적혀져있는 것을 확인할 수 있는데, 

이는 playlist/1이나 playlist/AU@Re... 등의 ID값에 따라 추가되는 URL이다.

 

2. Router.ts

constants.ts를 import하고, 해당 값들을 구조분해할당으로 받아서 사용한다.

구조분해할당을 하는 이유는, 참조로 접근하지않고, 바로 접근하기 위함이다.

 

import { ROUTER_PATH } from '@/constants/constants';

const Router = () => {
  const {
    SPLASH,
    HOME,
    MY_PAGE,
    PLAYLIST,
    VIDEO_ADD,
    BOOKMARK,
    BOOKMARK_CATEGORY_ADD,
    LOGIN,
    AUTHOR_DETAIL,
    MY_PAGE_EDIT,
    MY_UPLOAD_VIDEO,
    PLAYLIST_DETAIL,
    VIDEO_DETAIL,
    VIDEO_EDIT,
    KAKAO_REDIRECT,
    GOOGLE_REDIRECT,
  } = ROUTER_PATH;

  const router = createBrowserRouter([
    {
      element: <Layout />,
      children: [
        { path: SPLASH, element: <SplashPage /> },
        { path: KAKAO_REDIRECT, element: <KakaoOAuthHandler /> },
        { path: GOOGLE_REDIRECT, element: <GoogleOAuthHandler /> },
        { path: LOGIN, element: <LoginPage /> },
        {
          path: HOME,
          element: (
            <ProtectedRoute>
              <HomePage />
            </ProtectedRoute>
          ),
        },
        {
          path: MY_PAGE,
          element: (
            <ProtectedRoute>
              <Outlet />
            </ProtectedRoute>
          ),
          children: [
            { index: true, element: <MyPage /> },
            { path: MY_PAGE_EDIT, element: <MyPageEdit /> },
            { path: MY_UPLOAD_VIDEO, element: <MyUploadVideoPage /> },
            { path: VIDEO_EDIT, element: <VideoEditPage /> },
          ],
        },
        {
          path: '*',
          element: (
            <ProtectedRoute>
              <NotFoundPage />
            </ProtectedRoute>
          ),
        },
      ],
    },
  ]);

  return <RouterProvider router={router} />;
};

export default Router;

 

지정되어있는 URL을 제외한 모든 부분은 NotFundPage를 보여준다.

 

여기서 모든 요소가 PrortectedRoute로 감싸져있는 것을 확인할 수 있는데,

이는 사용자가 로그인을 했는지에 대한 여부를 판단하여 접근 허가/불가 여부를 판단하기 위함이다.

 

3. ProtectedRoute.ts

import { Navigate, useLocation } from 'react-router-dom';

import Spinner from '@/components/common/spinner/Spinner';
import { useUsers } from '@/hooks/useUsers';
import { ROUTER_PATH } from '@/constants/constants';

const ProtectedRoute = ({ children }: { children: React.ReactNode }) => {
  const { currentUserQuery } = useUsers();
  const location = useLocation();

  if (currentUserQuery.isLoading) {
    return <Spinner />;
  }

  if (!currentUserQuery.data) {
    return (
      <Navigate to={ROUTER_PATH.LOGIN} state={{ from: location }} replace />
    );
  }

  return <>{children}</>;
};

export default ProtectedRoute;

 

 

여기서 children은 보호된 라우터에 접근한 경우, 즉 로그인한 경우로 각 자식 컴포넌트를 렌더링한다

 

4. :playlist에 대한 Router 작성방법

<Link to={`/playlist/${music.list_id}`} key={music.list_id}>