안녕하세요! 웹 OB 김채현입니다.
이번에는 React Router에서 Outlet과 Layout을 활용하는 방법에 대해 아티클을 작성해보려고 합니다.
웹 페이지리를 구성할 때, 계속 공통적으로 적용되는 레이아웃이 있다면 이를 효율적으로 관리하는 것이 중요합니다.
이때 Outlet과 Layout을 활용하면 다중 레이아웃을 깔끔하게 구현할 수 있어, 페이지를 더 구조적으로 설계할 수 있습니다.
이번 아티클에서는 Outlet과 Layout이 무엇인지, 어떻게 사용하면 좋은지에 대해 함께 살펴보겠습니다.
Outlet이란?
Outlet은 부모 Route에서 하위 Route를 렌더링할 위치를 지정해주는 역할을 합니다.
React Router에서 특정 경로에 여러 중첩된 하위 경로가 있을 때, 부모 컴포넌트 안에 Outlet을 배치하여 하위 컴포넌트가 특정 위치에 표시되도록 합니다.
예를 들어, "관리자 페이지"가 있다고 가정해볼까요?
관리자 페이지에서는 관리하는 항목에 따라서 다양한 하위 페이지가 있을 수 있습니다.
아래 사진은 제가 했던 앱잼 프로덕트 "BEAT"의 관리자 페이지인데요,
이러한 페이지에서 Outlet을 사용하면 레이아웃을 고정하면서 하위 경로에 따라 컴포넌트를 다르게 렌더링할 수 있습니다.
"admin" 뒤에 "/promotion", "/user" 등을 붙여주면서 하위 경로를 접속하면
경로에 따라 해당하는 항목을 렌더링할 수 있습니다!!
Layout이란?
Layout 컴포넌트는 페이지 전체에서 공통적으로 사용되는 레이아웃을 정의하는 상위 컴포넌트입니다.
헤더, 사이드바, 푸터처럼 대부분의 페이지에서 동일하게 표시되어야 하는 레이아웃 요소들을 이곳에 정의할 수 있습니다.
위에서 예시로 봤던 페이지에서도 이렇게 헤더와 사이드바가 공유되고 있는 모습을 확인할 수 있습니다.
이렇게 Outlet과 Layout을 함께 사용하면 공통된 레이아웃을 정의할 수 있는데요,
이를 통해서 코드를 재사용하고 유지보수성을 높일 수 있습니다.
실습 과제에서 적용해보자!
이번 과제에서는 회원가입과 로그인을 한 유저는 마이 페이지를 접속할 수 있었습니다.
이때 회원가입, 로그인하는 페이지가 공통된 레이아웃을 공유하고,
마이 페이지 아래에 있는 페이지들이 공통된 레이아웃을 공유하고 있었는데요!
로그인 및 회원가입 페이지는 기본 레이아웃을 공유하고, 마이 페이지 하위에서는 마이 페이지에만 필요한 레이아웃을 사용하도록 설정하기 위해 Outlet을 사용해서 2개의 레이아웃을 정의했습니다.
import MyPageHeader from "@components/header/MyPageHeader";
import { Outlet } from "react-router-dom";
const MyPageLayout = () => {
return (
<>
<MyPageHeader />
<Outlet />
</>
);
};
export default MyPageLayout;
import Header from "@components/header/Header";
import { Outlet } from "react-router-dom";
const Layout = () => {
return (
<>
<Header />
<Outlet />
</>
);
};
export default Layout;
그리고 해당하는 해당하는 경로에 맞게 작성한 Layout을 지정하고 children으로 하위 컴포넌트를 렌더링할 수 있도록 router를 작성했습니다.
import Layout from "@components/layout/Layout";
import { createBrowserRouter } from "react-router-dom";
import MYPAGE_ROUTES from "./MyPageRoutes";
import Login from "@pages/Login";
import Signup from "@pages/Signup";
import MyPageLayout from "@components/layout/MyPageLayout";
const router = createBrowserRouter([
{
path: "/",
element: <Layout />,
children: [
{ index: true, element: <Login /> },
{ path: "login", element: <Login /> },
{ path: "signup", element: <Signup /> },
],
},
{
path: "/mypage",
element: <MyPageLayout />,
children: [...MYPAGE_ROUTES],
},
]);
export default router;
import Hobby from "@pages/Hobby";
import MyInfo from "@pages/MyInfo";
import { redirect } from "react-router-dom";
const requireAuth = () => {
const user = localStorage.getItem("user");
if (!user) {
alert("로그인 후 이용하세요.");
return redirect("/login");
}
return null;
};
const MYPAGE_ROUTES = [
{ index: true, element: <Hobby />, loader: requireAuth },
{ path: "info", element: <MyInfo />, loader: requireAuth },
{ path: "hobby", element: <Hobby />, loader: requireAuth },
];
export default MYPAGE_ROUTES;
마이페이지와 같은 경우에는 로그인을 한 유저만 접속이 가능하고, 하지 않은 유저는 로그인 페이지로 리다이렉트하도록 설정해야 합니다.
loader는 부로 컴포넌트에서 데이터를 요청하거나 초기화하는 로직을 분리하고,
페이지 이동중에 필요한 데이터 로딩을 관리하기 위해 사용합니다.
loader는 함수 형태로 작성되며, Router가 해당 경로로 이동할 때마다 실행됩니다.
따라서 requireAuth 함수를 정의해서 loader 속성에 추가하면
페이지가 로드될 때마다 로그인 여부를 확인하고, 미로그인 상태이면 자동으로 리다이렉트하도록 작성해주었습니다.
'4주차' 카테고리의 다른 글
Error Boundary로 에러 핸들링하기 (0) | 2024.11.12 |
---|---|
개발 어떤 방식으로 하세요? _ CDD : 컴포넌트 주도개발 (0) | 2024.11.12 |
Protected Route로 라우트 보호하기 (0) | 2024.11.12 |
TypeScript의 .d.ts 파일 🧐 (0) | 2024.11.12 |
타입스크립트의 타입 (0) | 2024.11.12 |