OI7MI

[React] SPA 페이지 이동: react-router-dom (Link, useParams) 본문

카테고리 없음

[React] SPA 페이지 이동: react-router-dom (Link, useParams)

OI7MI 2026. 1. 14. 03:31
리액트 라우터(React Router) : 페이지 이동 구현

리액트는 SPA(Single Page Application) 구조를 사용한다. 즉, 페이지를 이동하더라도 매번 서버로부터 새로운 HTML 파일을 받아오는 것이 아니라, 하나의 HTML 문서 위에서 URL 변경에 따라 렌더링되는 컴포넌트만 교체한다.

이때 URL 경로(path)에 따라 어떤 컴포넌트를 렌더링할지 매핑해 주는 라이브러리가 react-router-dom 이다.

이를 통해 브라우저 주소창의 변경을 감지하고, 새로고침 없이도 페이지 이동이 가능한 것처럼 동작하게 만들 수 있다.

 

 

 

1. 라이브러리 설치
npm install react-router-dom

 

 

2. 기본 구조

가장 먼저 Router로 전체를 감싸고, 그 안에 Routes와 Route를 배치한다.

  • Routes: 현재 URL과 일치하는 단 하나의 Route만 렌더링하기 위해 사용 (v5의 Switch에서 이름이 변경되었음)
  • Route: 특정 경로(path)와 그에 맞게 보여줄 컴포넌트(element)를 연결

 

3. 코드 적용
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";

function App() {
  return (
    <Router>
      <Routes>
        {/* /movie 경로면 Detail 컴포넌트 렌더링 */}
        <Route path="/movie" element={<Detail />} />
        
        {/* / (기본 경로)면 Home 컴포넌트 렌더링 */}
        <Route path="/" element={<Home />} />
      </Routes>
    </Router>
  );
}

 

💡 요약하자면 결국 컴포넌트들은 현재 브라우저의 URL을 주시하고 있다가, 주소가 바뀌면 미리 약속된 컴포넌트로 화면을 갈아 끼우는 역할을 한다. 사용자 입장에서는 페이지가 이동하는 것처럼 느껴지지만, 실제로는 하나의 문서 내에서 효율적으로 컴포넌트만 교체되는 것이다.

 

 

 


<Link> 컴포넌트 : 새로고침 없는 페이지 이동

앞서 리액트가 SPA(Single Page Application)라고 설명했다.

하지만 우리가 평소에 쓰는 <a> 태그를 그대로 사용하면 리액트의 가장 큰 장점 중 하나가 무력화된다.

 

 

 

1. 왜 <a> 태그를 쓰면 안 될까?

보통 HTML에서 사용하는 <a href="...">는 클릭 시 브라우저 전체를 새로고침한다. 즉, 서버로부터 아예 새로운 문서를 처음부터 다시 받아오는 것. 이렇게 되면 리액트 앱이 들고 있던 데이터(state)가 초기화되고, 화면이 깜빡거리며 SPA의 속도 이점을 누릴 수 없게 된다.

 

2. <Link> 컴포넌트의 역할

react-router-dom에서 제공하는 <Link> 컴포넌트는 브라우저의 새로고침을 막아준다.

대신 브라우저의 주소창만 바꾸고, 리액트가 바뀐 주소에 맞는 컴포넌트만 가로채서 다시 그릴 수 있도록 도와준다.

 

3. 코드

먼저 라이브러리에서 Link를 불러온 뒤, to 속성에 이동할 경로를 적어준다.

import { Link } from "react-router-dom";

function Movie({ title, id }) {
  return (
    <div>
      <h2>
        {/* 클릭 시 /movie 경로로 이동하지만, 새로고침은 발생하지 않음 */}
        <Link to="/movie">{title}</Link>
      </h2>
    </div>
  );
}

 

 

 


useParams : 어떤 데이터를 클릭했는지 알아내는 법

 

페이지가 하나뿐인 상세 페이지(Detail) 컴포넌트가 어떻게 수많은 데이터 중 내가 클릭한 정보만 가져올 수 있을까?

그 비밀은 URL에 담긴 id 값에 있다.

 

 

 

1. 주소에 "변수" 자리를 만들기 (App.js)

먼저 라우터를 설정할 때, id가 들어갈 자리를 비워줘야 한다. 이때 사용하는 것이 콜론(:)

// :id는 "이 자리에 값이 들어올 건데, 그 값을 id라고 부를게"라는 약속.

<Route path="/movie/:id" element={<Detail />} />

 

2. 링크에 실제 ID 값 넣어주기 (Movie.js)

사용자가 제목을 클릭하면 실제 그 영화의 id를 주소창에 넣어줘야 한다. 백틱을 사용해 주소를 동적으로 만든다.

// id가 123이라면 주소는 /movie/123이 된다.

<Link to={`/movie/${id}`}>{title}</Link>

 

3. 주소창의 ID 값 추출하기 (Detail.js)

이제 상세 페이지에서 주소창에 찍힌 123이라는 값을 읽어와야 한다. 이때 사용하는 Hook이 바로 useParams 다.

import { useParams } from "react-router-dom";

function Detail() {
  const { id } = useParams(); // 주소창의 :id 값을 가져옴
  console.log(id); // "123" 출력
  
  return <h1>Movie ID: {id}</h1>;
}

❗️const { id } = useParams() 처럼 객체로 감싸는 이유는? useParams가 값을 "객체" 형태로 반환하기 때문이다.
❗️객체로 주는 이유는? 주소창에는 변수가 하나만 있을 수도 있지만, 여러 개가 있을 수도 있기 때문이다.
비교해보기
  1. 전체로 받기: const params = useParams() → params는 { id: "123" } 이라는 덩어리가 된다. 그래서 꺼내 쓸 때 params.id라고 복잡하게 써야 함!
  2. 구조 분해 할당: const { id } = useParams() → 객체 안의 id라는 키(key)를 가진 값만 뽑아서 바로 id라는 변수에 담아줌!

즉, const { id } = useParams()는 "useParams가 준 객체 안에서 'id'만 꺼낼게!"라는 뜻.