[MainProject] 라우팅, 권한 설정
Routing
프로젝트의 페이지 라우팅 구성
##
//app.tsx
import { useState } from "react";
import { Routes, useLocation } from "react-router-dom";
import styled from "styled-components";
import { RouteList } from "./RouteList";
import Header from "./share/Header/Header";
import Footer from "./share/Footer";
import useAxiosInterceptor from "./hooks/useAxiosInterceptor";
import useRouteAnimation from "./hooks/useRouteAnimation";
const MainContent = styled.div`
flex-grow: 1;
`;
function App() {
const location = useLocation();
const [displayLocation, setDisplayLocation] = useState(location);
const [transitionStage, setTransitionStage] = useState("fadeIn");
useRouteAnimation(
location,
displayLocation,
setDisplayLocation,
setTransitionStage
);
useAxiosInterceptor();
const hideFooter = location.pathname === "/" || location.pathname === "/auth";
return (
<>
<Header />
<div
className={`${transitionStage}`}
style=
>
<MainContent>
<Routes location={displayLocation}>{RouteList}</Routes>
</MainContent>
{!hideFooter && <Footer />}
</div>
</>
);
}
export default App;
코드 분석
MainContent
const MainContent = styled.div`
flex-grow: 1;
`;
<MainContent>
가 부모 컨테이너 내에서 사용 가능한 공간을 모두 확장해서 채우도록 설정
–> 다른 컴포넌트들이 <MainContent>
아래로 배치될 때도 이 공간을 유지하게 된다.
예를 들어, <MainContent
>는 컨텐츠가 표시되는 주요 영역 <Header>
컴포넌트와 컨텐츠 영역 사이에서 콘텐츠가 확장되는 부분을 담당하게 된다. 이렇게 함으로써, 화면의 크기가 작아질 때도 페이지의 모든 영역이 화면에 표시되도록 한다.
location과 displayLocation 상태
const [displayLocation, setDisplayLocation] = useState(location);
useLocation
훅을 사용하여 현재 경로 정보를 가져오고, useState를
통해 displayLocation 상태를 관리
displayLocation 상태는 페이지 전환에 사용되는 위치 정보를 관리
transitionStage 상태
const [transitionStage, setTransitionStage] = useState("fadeIn");
페이지 전환 애니메이션의 단계를 관리하기 위한 상태 초기 값으로 ‘fadeIn’ 설정 -> 전체 웹 페이지에 애니매이션 적용
Footer hide
const hideFooter = location.pathname === "/" || location.pathname === "/auth";
<MainContent>
<Routes location={displayLocation}>{RouteList}</Routes>
</MainContent>;
{
!hideFooter && <Footer />;
}
/
, /auth
(로그인/회원가입)에는 hideFooter
를 통해 Footer
가 표시되지 않도록 설정하였다.
Route List
//RouteList.tsx
import { Route } from "react-router-dom";
import Payment from "./pages/order/Payment/Payment";
import Main from "./pages/main/Main";
import Auth from "./pages/users/Auth/Auth";
import Mypage from "./pages/mypage/Mypage";
import ShoppingCart from "./pages/order/ShoppingCart/ShoppingCart";
import StoreList from "./pages/store/StoreList";
import Map from "./pages/map/MapPage";
import SelectStore from "./pages/store/SelectStore";
import OrderComplete from "./pages/order/OrderComplete/OrderComplete";
import StoreDetail from "./pages/store/StoreDetail";
import PrivateRoute from "./PrivateRoute";
import NotFound from "./pages/notfound/NotFound";
import ChatList from "./pages/Chat/ChatList";
import PreferenceProductList from "./pages/preferenceProduct/PreferenceProductList";
export const Routes = [
{ path: "/", element: <Main /> },
{ path: "/select", element: <SelectStore /> },
{ path: "/map", element: <Map /> },
{ path: "/store", element: <StoreList /> },
{ path: "/store/:storeId", element: <StoreDetail /> },
{ path: "/product", element: <PreferenceProductList /> },
{ path: "*", element: <NotFound /> },
{ path: "/auth", element: <Auth />, isAuth: false },
{ path: "/payment", element: <Payment />, isAuth: true },
{ path: "/complete", element: <OrderComplete />, isAuth: true },
{ path: "/mypage", element: <Mypage />, isAuth: true },
{ path: "/cart", element: <ShoppingCart />, isAuth: true },
{ path: "/chatList", element: <ChatList />, isAuth: true, seller: true },
];
export const RouteList = (
<>
{Routes.map((route, index) => {
return route.isAuth === undefined ? (
<Route key={index} path={route.path} element={route.element} />
) : (
<Route
element={<PrivateRoute isAuth={route.isAuth} seller={route.seller} />}
>
<Route key={index} path={route.path} element={route.element} />
</Route>
);
})}
</>
);
Route 설정과 Routes 배열
Routes
배열을 정의하고, 각 경로에 대한 설정과 컴포넌트들을 연결하는 부분
export const Routes = [
{ path: "/", element: <Main /> },
// ... 다른 경로와 컴포넌트들의 설정
];
Routes
배열은 각 경로와 해당 경로에 해당하는 컴포넌트들을 객체 형태로 포함한다. path
속성은 경로를 나타내며, element
속성은 해당 경로로 이동했을 때 렌더링될 컴포넌트를 나타낸다.
RouteList 생성
RouteList는
Routes 배열을 기반으로 실제 Route 컴포넌트를 생성하는 부분
export const RouteList = (
<>
{Routes.map((route, index) => {
return route.isAuth === undefined ? (
<Route key={index} path={route.path} element={route.element} />
) : (
<Route
element={<PrivateRoute isAuth={route.isAuth} seller={route.seller} />}
>
<Route key={index} path={route.path} element={route.element} />
</Route>
);
})}
</>
);
Routes
배열을 순회하며 각 경로에 대한 Route 컴포넌트를 생성
isAuth
속성이 정의되어 있는 경우에는 PrivateRoute
컴포넌트로 감싸서, 인증 여부에 따라 보호된 경로 처리를 한다.
PrivateRoute 컴포넌트
인증과 권한에 따른 경로 보호 기능을 구현하는 부분
//PrivateRoute.tsx
import { Navigate, Outlet } from "react-router-dom";
import { LocalStorage } from "./utils/browserStorage";
import { LOCAL_STORAGE_KEY_LIST } from "./assets/constantValue/constantValue";
import { PrivateRouteProps } from "./assets/interface/Router.interface";
function PrivateRoute({ isAuth, seller = false }: PrivateRouteProps) {
if (seller) {
const memberRole = LocalStorage.get(LOCAL_STORAGE_KEY_LIST.MemberRole);
return memberRole === "SELLER" ? <Outlet /> : <Navigate to="/" />;
}
const accessToken = LocalStorage.get(LOCAL_STORAGE_KEY_LIST.AccessToken);
return isAuth === (accessToken !== null) ? <Outlet /> : <Navigate to="/" />;
}
export default PrivateRoute;
PrivateRoute
컴포넌트는 isAuth
와 seller
속성을 받아 인증 여부와 판매자 여부에 따라 경로 보호 기능을 구현하였다.
-
seller 속성이 true인 경우, 로컬 스토리지에서 회원 역할을 확인하여 판매자 역할인 경우
<Outlet />
을 반환하고, 아닌 경우 홈 페이지로 이동 -
그 외의 경우, 로컬 스토리지에서 액세스 토큰을 확인하여 인증 여부를 확인하고, 해당 여부에 따라 경로 보호 여부를 결정
<Outlet />
은 하위 경로의 컴포넌트들을 렌더링하는 역할을 한다. <Navigate to="/" />
는 경로를 홈 페이지로 이동시키는 역할을 한다.
댓글남기기