라우팅을 가장 기본적으로 설정하는 방법은 '정적 라우팅'이다.
Router 컴포넌트에서 미리 프로젝트에서 사용할 수 있는 경로들과 해당 경로로 접속했을 때 보여줄 컴포넌트를 모두 정의해두는 방식이다.
// Router.js
function Router() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Main />} />
<Route path="/detail" element={<Detail />} />
</Routes>
</BrowserRouter>
하지만 만약에 디테일 페이지를 100개 이상 쓸려고 한다면 라우트를 100개를 만들어야 써야할 것이다.
이러한 문제점을 해결하기 위한 것이 바로 '동적 라우팅' 이다.
Route를 설정할 때 URL의 전체 형태를 미리 정의하는 것이 아니라
특정 규칙을 정의한 후 규칙에 부합하는 URL의 경우에는 해당 element를 보여주게 설정하는 방식으로 해결하는 것이다.
동적 라우팅을 구현하는 방법은 Route 컴포넌트의 path prop에 : 기호를 활용하는 것이다.
경로/:문자열형태로 path를 설정하면 URL에서 경로/ 뒤에 무슨 글자가 오든 이 Route로 연결되게 된다.
// Router.js
function Router() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Main />} />
<Route path="/detail/:id" element={<Detail />} />
</Routes>
</BrowserRouter>
위 예시 코드와 같이 Route를 설정하게 되면 detail 뒤에 어떤 글자가 와도 모두 상세페이지 컴포넌트를 보여주게 된다.
즉, detail/1 ,detail/1000 , detail/1000000, detail/test 모두 상세페이지 컴포넌트로 연결된다.
여기서 : 기호 뒤에 붙는 id 와 같은 문자열이 path parameter 이다.
path parameter란 URL에 있는 값을 마치 매개변수(parameter)처럼 사용한다.
함수에서 매개변수의 이름을 자유롭게 지을 수 있는 것처럼 path parameter의 이름도 자유롭게 작성할 수 있다.
예시 코드에서는 detail/:id라고 path를 설정했으니까 path parameter의 이름을 id 로 설정하여
결과적으로 유저가 detail/1로 접속하면 id라는 이름으로 1이라는 값이 전달되는 것입니다
react-router-dom에서는 useParams hook을 제공해 준다.
useParams hook은 path parameter의 값을 편하게 가져올 수 있게 해주며
마치 state처럼 path parameter의 *값이 바뀌면 컴포넌트를 리렌더링 해주는 기능을 제공해 준다.
useParams는 받아온 값을 객체로 반환한다.
// useParams 활용 예시
import { useParams } from 'react-router-dom';
const params = useParams();
// { [path-parameter-name]: value }
// Router.js
function Router() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Main />} />
<Route path="/detail/:id" element={<Detail />} />
</Routes>
</BrowserRouter>
//Main.js
function Main() {
const [cardList, setCardList] = useState([]);
useEffect(() => {
fetch("api 주소")
.then((response) => response.json())
.then((data) => setCard(data));
}, []);
return(
<div className='main'>
</div>
)
그 안에 <Link>로 감싸고 경로를 /detail/${id}로 지정한다. 이렇게 되면 만들어진 요소를 선택할 때 마다
/detail/ 만들어진 요소의 아이디의 url로 이동하게 된다.
// Main.js
function Main() {
const [cardList, setCardList] = useState([]);
useEffect(() => {
fetch("api 주소")
.then((response) => response.json())
.then((data) => setCard(data));
}, []);
return(
<div className='main'>
{cardList.map((card) => {
<Link to={`/detail/${card.id}`} key={card.id}>
<Card card={card}></Card>;
</Link>
);
})}
</div>
)
여기서 가져온 매개변수는 객체로 받아와지기 때문에 구조분해할당을 통해서 가져오면 좋다.
// Detail.js
import { useParams } from 'react-router-dom';
function Detail(){
const { id } = useParams();
return(
<div>
<p>현재는 디테일? 페이지입니다.<p/>
</div>
)
}
// Detail.js
import React,{ useState } from "react";
import { useParams } from 'react-router-dom';
function Detail(){
const { id } = useParams();
const [detailData, setDetailData] = useState()
useEffet(()=>{
fetch(`불러올 디테일 주소/${ id }`) // useParams 사용
.then(res=>res.json())
.then(data=>setDetailData(data)) // api 데이터 저장
})
return(
<div>
<p>현재는 디테일? 페이지입니다.<p/>
</div>
)
}
// Detail.js
import React,{ useState } from "react";
import { useParams } from 'react-router-dom';
function Detail(){
const { id } = useParams();
const [detailData, setDetailData] = useState()
useEffet(()=>{
fetch(`불러올 디테일 주소/${ id }`) // useParams 사용
.then(res=>res.json())
.then(data=>setDetailData(data)) // api 데이터 저장
})
return(
<div>
<p>`현재는 디테일 ${detailData.id} 페이지입니다.`<p/>
</div>
)
}