구현 배경
- 사용자에게 보여지게 될 페이지를 로그인 여부에 따라 구분할 필요가 있었다.
- 로그인한 사용자에게는 기능 사용이 가능한 메인 페이지를 보여주고, 로그인하지 않은 사용자에게는 로그인 페이지만 보여지도록 해야했다.
- 그리고 이미 로그인을 완료한 사용자는 로그인 페이지 접근을 막아야했다.
로직
- 라우트 처리를 담당하는 최상위 컴포넌트에서 로그인 전역 상태를 이용하여 분기 처리한다.
- 로그인을 완료한 사용자에게는 메인 페이지를, 로그인하지 않은 사용자에게는 로그인 페이지만 보이도록 처리한다.
코드
- Zustand store로부터 로그인 상태를 import한다.
/** 로그인 전역 상태 */
const { isLoggedIn } = useAuthStore();
- 그리고 라우트할 컴포넌트들은 추후 필요한 라우트를 간편하게 추가하기 위해, 그리고 유지보수할 작업이 생길 경우를 고려하여 아래와 같이 배열로 구현하였다. 보호 여부를 구분하기 위해 isPrivate 변수를 선언하여 지정해주었다.
/** 라우트 목록 */
const routeList = [
{
path: "/",
element: <Home />,
isPrivate: true,
},
{
path: "/login",
element: <Login />,
isPrivate: false,
},
];
- Protected route 컴포넌트를 아래와 같이 작성하였다.
- 로그인 상태가 true일 시, 렌더링할 component를 props로 내려받은 것을 확인할 수 있다.
- 비 로그인 상태일 시, 로그인 페이지로 리다이렉트한다.
import { Navigate, Outlet } from "react-router-dom";
import useStore from "../../store/authStore";
interface ProtectedRouteProps {
component: React.ReactElement;
}
const ProtectedRoute = ({ component }: ProtectedRouteProps) => {
const { isLoggedIn } = useStore();
if (!isLoggedIn) {
/** 비 로그인 상태일 시, 로그인 페이지 이동 */
return <Navigate to="/login" replace={true} />;
}
/** 컴포넌트 렌더링 */
return component;
};
export default ProtectedRoute;
- react-router-dom을 사용하여 라우트 목록을 아래와 같이 작성한다.
- 보호 여부를 의미하는 isPrivate 변수를 이용하여 분기처리하였다.
- 만약 isPrivated이 true인 경우, 비 로그인 상태일 시 ProtectedRoute 컴포넌트에 의해 로그인 페이지로 리다이렉트되도록 구현하였다.
- 그리고 로그인 페이지의 경우, 보호 받아야할 컴포넌트는 아니지만 로그인 상태일 시 접근을 막아야하여 조건을 추가해주었다.
<BrowserRouter>
<ThemeProvider theme={theme[themeMode]}>
<GlobalStyle />
<CalendarStyle />
<Layout>
<UtilsBox themeMode={themeMode} handleFunc={changeTheme} />
<Routes>
{routeList.map((route) => {
const isAuthenticated = isLoggedIn;
if (route.isPrivate) {
return (
<Route
key={route.path}
path={route.path}
element={<ProtectedRoute component={route.element} />}
/>
);
} else {
if (route.path === "/login" && isAuthenticated) {
return (
<Route
key={route.path}
path={route.path}
element={<Navigate to="/" replace />}
/>
);
}
return (
<Route
key={route.path}
path={route.path}
element={route.element}
/>
);
}
})}
<Route path="/*" element={<Navigate to="/" replace />} />
</Routes>
</Layout>
</ThemeProvider>
</BrowserRouter>