<리액트를 다루는 기술> 13장 리액트 라우터로 SPA 개발하기를 공부하면서 정리한 내용입니다📚
중간에 모르는 것들은 따로 서치를 해서 공부했습니다.
🍧SPA: 싱글 페이지 애플리케이션, 하나의 페이지로 이루어진 애플리케이션
🍧라우팅 : 사용자가 요청한 URL에 따라 알맞은 페이지를 보여주는 것
npm install react-router-dom
index.js 파일에 BrouserRouter
컴포넌트로 감싸면 됩니다.
index.js
import {BrowserRouter} from 'react-router-dom'
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
<Routes>
<Route path="주소규칙" element={보여줄 컴포넌트} />
</Routes>
❗ 컴포넌트는 <Routes> 안에 있어야합니다.
❗예시에서는 App 컴포넌트에 라우트를 작성했습니다.
리액트 라우터를 사용하는 프로젝트에서는 a 태그를 사용하면 안됩니다.
Link 컴포넌트에는 페이지를 새로 불러오는 것을 막고 History API를 통해 주소만 바꿔주는 기능이 내장되어 있습니다.
< Link to="경로">링크 이름< /Link>
예)
import { Link } from "react-router-dom";
function Home() {
return (
<div>
<h1>홈</h1>
<p>가장 먼저 보여지는 페이지입니다.</p>
<ul>
<li>
<Link to="/about">소개</Link>
</li>
(...)
</ul>
</div>
);
}
URL 파라미터: 주로 ID, 이름을 사용하여 특정 데이터를 조회할 때 사용
쿼리스트링: 키워드 검색, 페이지네이션, 정렬방식 등 데이터 조회에 필요한 옵션을 전달받을 때 사용
Route 컴포넌트의 path props를 통해 설정합니다.
예시)
App.js에 새로운 라우트를 작성합니다.
<Routes>
<Route element={<Layout />}>
<Route index element={<Home />} />
//index = path="/"
<Route path="/about" element={<About />} />
<Route path="/profile/:username" element={<Profile />} />
</Routes>
/profiles/:username
과 같이 경로에 :
를 사용하여 설정합니다./profiles/:username/:field
같이 여러번 써먹을 수 있습니다.Home.js
import { Link } from "react-router-dom";
function Home() {
return (
<div>
<h1>홈</h1>
<p>가장 먼저 보여지는 페이지입니다.</p>
<ul>
<li>
<Link to="/about">소개</Link>
</li>
<li>
<Link to="/profile/soonmac">soonmac의 프로필</Link>
</li>
<li>
<Link to="/profile/gildong">gildong의 프로필</Link>
</li>
<li>
<Link to="/profile/void">존재하지 않은 프로필</Link>
</li>
<li>
<Link to="/articles">게시글 목록</Link>
</li>
</ul>
</div>
);
}
Profile.js
import { useParams } from "react-router-dom";
const data = {
soonmac: {
name: "순대",
description: "리액트 공부중",
},
gildong: {
name: "홍길동",
description: "홍길동전 주인공",
},
};
function Profile() {
const params = useParams();
const profile = data[params.username];
return (
<div>
<h1>사용자 프로필</h1>
{profile ? (
<div>
<h2>{profile.name}</h2>
<p>{profile.description}</p>
</div>
) : (
<p>존재하지 않는 프로필입니다</p>
)}
</div>
);
}
const params = useParams();
const profile = data[params.username];
import {useSearchParams } from "react-router-dom";
//useSearchParams import하기
function About() {
const [searchParams, setSearchParams] = useSearchParams();
//useSearchParams(쿼리파라미터 객체, 쿼리파라미터 객체를 업데이트하는 함수)
//useState랑 비슷함
const detail = searchParams.get('detail');
const mode = searchParams.get('mode');
const onToggleDetail = () => {
setSearchParams({mode, detail: detail === 'true' ? false: true})
}
const onIncreaseMode = () => {
const nextMode = mode === null ? 1 : parseInt(mode) + 1;
setSearchParams({mode: nextMode, detail})
}
console.log(searchParams);
return(
<div>
<h1>소개</h1>
<p>리액트 라우터를 사용해 보는 프로젝트입니다.</p>
<p>detail: {detail}</p>
<p>mode: {mode}</p>
<button onClick={onToggleDetail}>Toggle detail</button>
<button onClick={onIncreaseMode}>mode + 1</button>
</div>
)
}
const [searchParams, setSearchParams] = useSearchParams();
🍧useSearchParams(쿼리파라미터를 조회하거나 수정하는 메서드들이 담긴 객체, 업데이트 함수)
❗ 쿼리파라미터 조회할 때 값은 무조건 문자열 타입!
const onToggleDetail = () => {
setSearchParams({mode, detail: detail === 'true' ? false: true})
}
(true라고 하지 않고 'true'라고 썼음)
❗ 숫자를 다룬다면 parseInt를 사용하여 숫자타입으로 변환한다
const onIncreaseMode = () => {
const nextMode = mode === null ? 1 : parseInt(mode) + 1;
setSearchParams({mode: nextMode, detail})
}
여기서 게시글을 클릭하면
게시글 밑에 게시글 목록이 뜨도록 만듭시다!
🍧Outlet : Route의 children으로 들어가는 JSX 엘리먼트를 보여주는 컴포넌트
- 각 페이지 컴포넌트가 보여져야하는 부분에 Outlet 컴포넌트를 사용하면된다
<Route path="/articles" element={<Articles />}>
<Route path=":id" element={<Article />} />
</Route>
function Articles() {
return (
<div>
<Outlet />
//여기에 children인 Article 컴포넌트가 보여짐
<ul>
<li>
<Link to="/articles/1">게시글 1</Link>
</li>
<li>
<Link to="/articles/2">게시글 2</Link>
</li>
<li>
<Link to="/articles/3">게시글 3</Link>
</li>
</ul>
</div>
);
}
layout.js
function Layout() {
return(
<div>
<header style={{background:'lightgray',padding: 16, fontSize:24}}>
헤더
</header>
<main>
<Outlet />
</main>
</div>
)
}
🍧useNavigate: Link 컴포넌트를 사용하지 않고 다른 페이지로 이동해야하는 상황
Layout.js
function Layout() {
const navigate = useNavigate();
const goBack = () => {
navigate(-1)
//파라미터가 숫자 타입 : 양수 - 앞으로 가기 / 음수 - 뒤로 가기
}
const goArticles = () => {
navigate('/articles',{replace: true})
//{ replace: true } : 뒤로가기를 눌렀을 때 전의 전 페이지가 나옴
}
return(
<div>
<header style={{background:'lightgray',padding: 16, fontSize:24}}>
<button onClick={goBack}>뒤로가기</button>
<button onClick={goArticles}>게시글 목록</button>
</header>
<main>
<Outlet />
</main>
</div>
)
}
🍧NavLink : 링크에서 사용하는 경로가 현재 라우트의 경로와 일치하는 경우 특정 스타일 or CSS 클래스 적용하는 컴포넌트
✨NavLink의 style과 className은 { isActive: boolean }을 파라미터로 전달받는다.
<NavLink style={({isActive}) => isActive ? activeStyle : undefined}
<NavLink className={({isActive}) => isActive ? 'active' : undefined}
예시)
import { NavLink, Outlet } from "react-router-dom";
function 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>
)
};
이런식으로 해당하는 글 항목에 스타일이 들어간다.
🍧 * : 와일드카드 문자. 아무 텍스트나 매칭한다. 상단에 위치하는 라우트들의 규칙을 모두 확인하고 일치하는 라우트가 없다면 이 라우트가 화면에 나타난다.
예시)
App.js
function App() {
return (
<Routes>
<Route element={<Layout />}>
<Route index element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/profile/:username" element={<Profile />} />
</Route>
<Route path="/articles" element={<Articles />}>
<Route path=":id" element={<Article />} />
</Route>
<Route path="/login" element={<Login />} />
<Route path="/mypage" element={<MyPage />} />
<Route path="*" element={<NotFound />} />
</Routes>
);
}
🍧Navigate 컴포넌트: 컴포넌트를 화면에 보여주는 순간 다른 페이지로 이동하고 싶을 때 사용 (리다이렉트)
Login.js
function Login() {
return <div>로그인 페이지</div>
}
export default Login;
MyPages.js
import { Navigate } from "react-router-dom";
function MyPage() {
const isLoggedIn = false;
if(!isLoggedIn) {
return <Navigate to ="/login" replace={true} />
}
//isLoggedIn이 false인 경우 : 로그인 페이지로 리다이렉트
// replace props를 통해 '뒤로가기' 버튼을 눌렀을 때 페이지 전의 페이지로 이동하게끔
return <div>마이페이지</div>
}
export default MyPage;
<리액트를 다루는 기술> - 김민준(벨로퍼트), 길벗