웹 사이트에 회원가입을 해야지만 이용할 수 있는 페이지가 있다. 이처럼 누구나 접속할 수 있는 경로를 공개 라우트, 로그인한 사용자만 접속 가능한 경로를 비공개 라우트라고 한다.
예제
회원가입을 해야지만 이용할 수 있는 비공개 라우트와 누구나 접근 가능한 공개 라우트를 설정하는 예제이다. 이를 위해 RequireAuth 컴포넌트를 사용해 비공개 라우트를 보호하고, Layout 컴포넌트를 통해 공통 레이아웃을 정의한다.
useAuth.tsx
import type {FC, PropsWithChildren} from "react";
import {createContext, useCallback, useContext, useState} from "react";
import * as U from "../utils";
// LoggedUser 타입 정의: email과 password를 포함
export type LoggedUser = {
email: string
password: string
}
// Callback 타입 정의: 인수가 없고 반환 값이 없는 함수
type Callback = () => void
// ContextType 타입 정의: 인증 관련 메서드와 loggedUser 상태를 포함
type ContextType = {
loggedUser?: LoggedUser
signup: (email: string, password: string, callback?: Callback) => void
login: (email: string, password: string, callback?: Callback) => void
logout: (callback?: Callback) => void
}
// AuthContext 생성: 기본값으로 각 메서드를 빈 함수로 설정
export const AuthContext = createContext<ContextType>({
signup: (email: string, password: string, callback?: Callback) => {
},
login: (email: string, password: string, callback?: Callback) => {
},
logout: (callback?: Callback) => {
}
})
// AuthProviderProps 타입 정의 (현재는 빈 객체)
type AuthProviderProps = {}
// AuthProvider 컴포넌트 정의: 인증 상태와 메서드를 제공
export const AuthProvider: FC<PropsWithChildren<AuthProviderProps>> = ({children}) => {
const [loggedUser, setLoggedUser] = useState<LoggedUser | undefined>(undefined); // loggedUser 상태 정의
// signup 메서드 정의: 새로운 사용자 설정
const signup = useCallback((email: string, password: string, callback?: Callback) => {
const user = {email, password}
setLoggedUser(_ => ({email, password})); // loggedUser 상태 업데이트
U.writeObjectP('user', user).finally(() => callback && callback())
}, []);
// login 메서드 정의: 사용자 로그인 설정
const login = useCallback((email: string, password: string, callback?: Callback) => {
setLoggedUser(_ => ({email, password})); // loggedUser 상태 업데이트
callback && callback();
}, []);
// logout 메서드 정의: 사용자 로그아웃 설정
const logout = useCallback((callback?: Callback) => {
setLoggedUser(undefined); // loggedUser 상태 초기화
callback && callback();
}, []);
// Context 값 설정
const value = {
loggedUser,
signup,
login,
logout
}
// AuthContext.Provider를 사용하여 하위 컴포넌트에 값 제공
return <AuthContext.Provider value={value} children={children}/>
}
// useAuth 훅 정의: AuthContext의 값을 쉽게 사용하기 위해
export const useAuth = () => {
return useContext(AuthContext); // AuthContext의 값을 반환
}
Layout.tsx
Layout 컴포넌트는 내비게이션 바와 푸터를 포함하여 공통 레이아웃을 정의한다. Outlet을 사용해 하위 라우트를 렌더링 한다.
import {Outlet} from "react-router-dom";
import NavigationBar from "./NavigationBar";
import Footer from "./Footer";
export default function Layout() {
return (
<>
<NavigationBar/>
<Outlet/>
<Footer/>
</>
)
}
RequireAuth.tsx
RequireAuth 컴포넌트는 사용자가 인증되지 않은 경우 이전 페이지로 리디렉션 한다. useAuth 훅을 사용해 현재 로그인 상태를 확인한다.
import type {FC, PropsWithChildren} from "react";
import {useAuth} from "../../contexts";
import {useNavigate} from "react-router-dom";
import {useEffect} from "react";
type RequireAuthProps = {}
const RequireAuth: FC<PropsWithChildren<RequireAuthProps>> = ({children}) => {
const {loggedUser} = useAuth();
const navigate = useNavigate();
useEffect(() => {
if (!loggedUser) navigate(-1)
}, [loggedUser, navigate])
return <>{children}</>
};
export default RequireAuth
RoutesSetup.tsx
RoutesSetup 컴포넌트는 모든 라우트를 설정한다. Layout 컴포넌트를 사용해 공통 레이아웃을 제공하고, RequireAuth를 사용해 비공개 라우트를 보호한다.
import {Route, Routes} from "react-router-dom";
import NoMatch from "./NoMatch";
import Layout from "./Layout";
import Board from "../pages/Board";
import LandingPage from "./LandingPage";
import Login from "./Auth/Login";
import Logout from "./Auth/Logout";
import SignUp from "./Auth/SignUp";
import RequireAuth from "./Auth/RequireAuth";
export default function RoutesSetup() {
return (
<Routes>
<Route path={"/"} element={<Layout/>}>
<Route index element={<LandingPage/>}/>
<Route
path={"/board"}
element={
<RequireAuth>
<Board/>
</RequireAuth>
}/>
<Route path={"*"} element={<NoMatch/>}/>
</Route>
<Route path={"/signup"} element={<SignUp/>}/>
<Route path={"/login"} element={<Login/>}/>
<Route
path={"/logout"}
element={
<RequireAuth>
<Logout/>
</RequireAuth>
}/>
</Routes>
)
}
728x90
'Javascript > React' 카테고리의 다른 글
[React] 리액트 라우터 (0) | 2024.08.01 |
---|---|
[React] React Beautiful DnD 라이브러리 (0) | 2024.07.31 |
[React] React DnD 라이브러리 (0) | 2024.07.31 |
[React] 리덕스 미들웨어 (0) | 2024.07.29 |
리듀서 활용하기 (0) | 2024.07.22 |