싱글페이지앱이란 문자그대로 단일페이지로 이루어진 앱을 의미한다. 페이지를 이동할 때 anchor 태그를 활용해 새로운 html을 불러오는 게 아니라 index.html 하위의 DOM을 갈아 끼우면서 다른 페이지를 보여주는 방식이다. 전체 페이지를 다시 렌더링하지 않고 변경되는 부분만을 갱신하므로 새로고침이 발생하지 않는다는 장점이 있다.
리액트는 이러한 싱글페이지앱 제작을 가능하게 하며, 그 과정에서 라우터 라이브러리를 사용한다. 가장 많이 사용하는 라우터 컴포넌트에는 BrowserRouter와 HashRouter가 있다.
BrowserRouter
- HTML5를 지원하는 브라우저의 주소를 감지
- 예를 들어, https://movie.daum.net/moviedb/main?movieId=62708
HashRouter
- 해시 주소를 감지
- http://tistory.com/#test
이 중에서 BrowserRouter에 대해 더 알아보자.
아래와 같이 BrowserRouter가 인식하는 브라우저의 주소 체계에서
https://movie.daum.net/moviedb/main?movieId=62708
뒷 부분의 숫자가 바뀌면 다른 페이지가 보여진다. 예를 들면 지금은 [아바타] 영화 설명페이지이고 '62708'을 '115401'으로 바꾸면 [영웅] 영화 설명페이지로 바뀐다.
이렇게 페이지의 주소체계에 대해 이해했으므로 이것을 어떻게 리액트로 코딩하는지 알아보자.
예시로 다음과 같은 싱글페이지앱 형태의 영화페이지를 제작해보려고 한다.
메인 페이지 > 영화 목록 페이지 > 영화 상세 페이지
먼저 라우터를 설치해준다.
npm install react-router-dom
그 후 App.js 상단에서 BrowserRouter를 import 해준다.
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
일단 아래와 같이 작성하여 메인페이지(/)에 Home 컴포넌트를 연결해주었다. 그 후 하위 페이지 주소로 영화 목록 페이지(/movie), 영화 상세 페이지(/movie/detail/:id)를 작성하고 각각의 컴포넌트와 연결해 주었다.
import Home from "./Home";
import Movie from "./Movie";
import Detail from "./Detail";
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/movie" element={<Movie />} />
<Route path="/movie/detail/:id" element={<Detail />} />
</Routes>
</Router>
);
}
Home.js에서는 다음과 같이 Link 컴포넌트를 이용하여 /movie 페이지와 연결해주었다.
import { Link } from "react-router-dom";
function Home() {
return (
<div>
<Link to="/movie">
go to movie page
</Link>
</div>
);
}
Movie.js에서는 다음과 같이 Link 컴포넌트를 이용하여 /movie/detail/:id 페이지와 연결해주었다. /movie 페이지에서는 각각의 영화에 해당하는 figure를 클릭하면 해당 영화의 id를 Link 컴포넌트의 to 속성에 받아와서 주소를 만들고 연결된다.
import { Link } from "react-router-dom";
function Home() { ...
return (
<Link to={`/movie/detail/${id}`}>
<figure className={styles.figure}>
...
</figure>
</Link>
);}
위 코드에서 id는 주소의 파라미터 역할을 하며, App.js에서 라우트 컴포넌트 작성시 아래와 같이 파라미터 앞에 :를 붙여준다.
<Route path="/movie/detail/:id" element={<Detail />}/>
마지막으로 Detail.js에서 다음과 같이 useParams을 사용하여 Movie.js의 id를 받아오면 된다.
import { useParams } from "react-router-dom";
function Detail() {
const { id } = useParams();
const URL = `https://yts.mx/api/v2/movie_details.json?movie_id=${id}`;
위의 예시에서는 영화 별로 상세페이지가 나타나게 하였지만, 만약 영화에 상관없이 하나의 페이지로 연결되게 하고 싶다면 주소 뒤에 /* 을 붙여 주면 된다. 또한, 정의하지 않은 경로 접속시에 NotFound 컴포넌트를 출력하고 싶다면 주소에 *만 적어주면 된다.
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/movie" element={<Movie />} />
<Route path="/movie/Detail/*" element={<Product />}></Route>
<Route path="*" element={<NotFound />}></Route>
</Routes>
</Router>
);
}
라우팅: 페이지의 주소만 바뀔 뿐 새로고침 되지는 않는다.
a 태그: 페이지의 주소가 바뀜과 동시에 새로고침된다.
리액트 특성 상 새로고침 될 때 마다. 페이지를 구성하는 무성한 변수를 가지는 컴포넌트의 값들이 지워지고 새로 계산되기 때문에 페이지 주소가 바뀔 때마다 새로고침이 된다면 속도가 저하될 수 밖에 없다. 따라서 새로고침이 필수적인 상황이 아닌 이상 a 태그가 아닌 라우팅을 사용하여야 한다.