안녕하세요, 코린이의 코딩 학습기 채니 입니다.
[리액트를 다루는 기술]의 책을 참고하여 포스팅한 개인 공부 내용입니다.
리액트 라우터로 SPA 개발하기
리액트 라우터 부가 기능
useNavigate
- Link 컴포넌트를 사용하지 않고 다른 페이지로 이동해야하는 상황에 사용하는 Hook
Layout.js
import { Outlet, useNavigate } from "react-router-dom";
// 헤더 레이아웃
const Layout = () => {
const navigate = useNavigate();
const goBack = () => {
// 이전 페이지로 이동
navigate(-1);
};
const goArticles = () => {
// 게시글 목록으로 이동
navigate('/articles');
}
return (
<div>
<header style={{background: 'lightgray', padding: 16, fontSize: 24}}>
<button onClick={goBack}>뒤로가기</button>
<button onClick={goArticles}>게시글 목록</button>
</header>
<main>
<Outlet />
</main>
</div>
)
}
export default Layout;
뒤로 가기 버튼을 누르면 이전 페이지로 이동, 게시글 목록 버튼을 누르면 게시글 목록 페이지로 이동하는 것을 확인할 수 있습니다.
만일 2페이지 전으로 이동을 원한다면 'navigate(-2)', 앞 페이지로 이동을 원한다면 'navigate(1)'로 해줄 수 있습니다.
이 중 replace 옵션이 있는데, 페이지를 이동할 때 현재 페이지를 페이지 기록에 남기지 않습니다.
Layout - goArticles
const goArticles = () => {
// 게시글 목록으로 이동
navigate('/articles', { replace: true});
}
영상을 확인해보면 뒤로 가기 버튼 클릭 시 직전 페이지인 About이 나와야할 것 같지만, Home 페이지가 나온 것을 확인할 수 있습니다.
NavLink
- 링크에서 사용하는 경로가 현재 라우트의 경로와 일치하는 경우 특정 스타일 또는 CSS 클래스 적용
- style과 className은 { isActive: boolean }을 파라미터로 받는 함수 타입의 값을 전달해줌
예시
<NavLink style={({isActive} => isActive ? activeStyle : undefind} />
<NavLink style={(isActive} => isActive ? 'active' : undefind} />
Articles.js
import { NavLink, Outlet } from 'react-router-dom'
const Articles = () => {
const activeStyle = {
color: 'green',
fontSize: 21
}
return(
<div>
<Outlet />
<ul>
<li>
<NavLink to="/articles/1" style={({ isActive }) => isActive ? activeStyle : undefined}>게시글 1</NavLink>
</li>
<li>
<NavLink to="/articles/2" style={({ isActive }) => isActive ? activeStyle : undefined}>게시글 2</NavLink>
</li>
<li>
<NavLink to="/articles/3" style={({ isActive }) => isActive ? activeStyle : undefined}>게시글 3</NavLink>
</li>
</ul>
</div>
)
}
export default Articles;
{isActive: false, isPending: false}을 반환하고 이 중 isActive를 이용해 경로가 일치하는 경우를 찾아 스타일을 적용하였습니다.
하지만 위 코드를 보면 중복이 많아 이를 리팩토링 하여 사용하는 것이 적합할 것 같습니다.
Article.js
import { NavLink, Outlet } from 'react-router-dom'
const Articles = () => {
return(
<div>
<Outlet />
<ul>
<ArticleItem id={1} />
<ArticleItem id={2} />
<ArticleItem id={3} />
</ul>
</div>
)
};
const ArticleItem = ({ id }) => {
const activeStyle = {
color: 'green',
fontSize: 21
}
return (
<li>
<NavLink to={`/articles/${id}`} style={({ isActive }) => isActive ? activeStyle : undefined}>
게시글 {id}
</NavLink>
</li>
);
};
export default Articles;
NotFound 페이지 만들기
- 사전에 정의되지 않는 경로에 사용자가 진입했을 때 보여주는 페이지
NotFound.js
const NotFound = () => {
return(
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: 64,
position: 'absolute',
width: '100%',
height: '100%'
}}
>
404
</div>
)
}
export default NotFound;
App.js
import './App.css';
import Home from './pages/Home';
import About from './pages/About';
import { Routes, Route } from 'react-router-dom';
import Profile from './pages/Profile';
import Articles from './pages/Articles';
import Article from './pages/Article';
import Layout from './Layout';
import NotFound from './NotFound';
function App() {
return (
<Routes>
<Route path='/' element={<Layout />}>
<Route index element={<Home />} />
<Route path='/about' element={<About />} />
<Route path='/profiles/:username' element={<Profile />} />
</Route>
<Route path='/articles' element={<Articles />} >
<Route path=':id' element={<Article />} />
</Route>
<Route path='*' element={<NotFound />} />
</Routes>
);
}
export default App;
* wildcard 문자로 아무 텍스트나 매칭한다는 뜻을 가지고 있습니다.
해당 라우트 엘리먼트의 상단에 위치하는 라우트들을 모두 확인 후 일치하는 라우트가 없다면 해당 라우트가 화면에 나타나게 됩니다.
Navigate 컴포넌트
- 컴포넌트를 화면에 보여주는 순간 다른 페이지로 이동하고 싶을 때 사용 (리다이렉트 처리)
- 예) 로그인 필요한 페이지에 로그인을 하지 않고 접근 시 로그인 페이지로 리다이렉트 처리할 때 사용
Login.js
const Login = () => {
return <div>로그인 페이지</div>;
}
export default Login;
MyPage.js
import { Navigate } from "react-router-dom";
const MyPage = () => {
const isLoggedIn = false;
if(!isLoggedIn) {
return <Navigate to="/login" replace={true} />;
}
return <div>마이페이지</div>
}
export default MyPage;
추후 로그인 상태에 따라 isLoggedIn 값을 변경해주어 로그인 여부에 따라 페이지 렌더링을 달리 해줄 수 있습니다.
로그인을 하지 않고 mypage에 접속한다면 이를 검사하여 Navigate 컴포넌트를 통해 login 페이지로 리다이렉트 시켜줍니다.
또한 replace 옵션을 이용하여 두 페이지 전의 페이지로 이동하도록 하였습니다.
(왜냐하면 Home - MyPage → Login 리다이렉트 처리가 되었으므로 Login 페이지에서 뒤로 가기 버튼을 눌렀을 때 MyPage로 이동하게 됨 - 그럼 MyPage와 Login 리다이렉트가 반복 처리 되므로 사용자 불편! 따라서 그 전전 페이지인 Home으로 이동하게끔 replace 옵션 사용!)