특정 경로에 진입시 사용자 인증이 되어있지 않으면 리다이렉트하는 기능이 필요했다.
처음에 구현한 것은 아래와 같이
'/profile'의 Profile 컴포넌트가 마운트 됐을 때 store의 isLoggedIn를 참조하여 !isLoggedIn일시 '/auth'로 이동하게 했다. 문제는 없지만 이러한 페이지가 많을 경우에는 유지보수에 좋지 못할 수도 있다.
function Profile() {
const { isLoggedIn } = useSelector((state: RootState) => state.init);
// 비 로그인 시 home으로 이동
useEffect(() => {
if (!isLoggedIn) {
navigate('/auth');
}
}, [isLoggedIn]);
}
다음은 PrivateRoute를 활용하는 방법이다. 간단하게 isLoggedIn만 확인하고 navigate시키는 장치를 원하는 컴포넌트에 씌워준다고 생각하면 된다.
children을 props로 받아와야하기 때문에 ReactNode를 import해준다.
// PrivateRoute.tsx
import { ReactNode, useEffect } from 'react';
function PrivateRoute({ children }: { children: ReactNode }) {
const { isLoggedIn } = useSelector((state: RootState) => state.init);
const navigate = useNavigate();
useEffect(() => {
if (!isLoggedIn) {
navigate('/auth');
alert('로그인이 필요합니다.');
}
}, [isLoggedIn, navigate]);
if (!isLoggedIn) {
return null;
}
return <>{children}</>;
}
export default PrivateRoute;
// App.tsx
<Wrapper>
<Routes>
<Route path="/" element={<Navigate to="/home" />} />
<Route path="/home" element={<Home />} />
<Route path="/rate" element={<PrivateRoute><Rate /></PrivateRoute>} />
<Route path="/auth" element={<Auth />} />
<Route path="/profile" element={<PrivateRoute><Profile /></PrivateRoute>} />
<Route path="/*" element={<NotFound />} />
</Routes>
</Wrapper>
'/auth' 페이지에선 반대되는 기능을 활용할 수 있도록 다음과 같이 수정했다.
useEffect(() => {
if (authMatch && isLoggedIn) {
navigate('/home');
return
}
if (authMatch && !isLoggedIn) {
return;
}
if (!isLoggedIn) {
navigate('/auth');
alert('로그인이 필요합니다.');
}
}, [isLoggedIn, navigate, authMatch]);
if (!authMatch && !isLoggedIn) {
return null;
}
return <>{children}</>;
계속 느끼는 건데 리액트는 정말 분리와 재사용의 연속인 것 같다.