포스트

[이제와서 시작하는 React 마스터하기 #9] React Router - 페이지 이동하기

[이제와서 시작하는 React 마스터하기 #9] React Router - 페이지 이동하기

React Day 9 - 버튼을 클릭하면 다른 페이지로 이동하게 만들고 싶으신가요? React Router로 SPA(Single Page Application)를 만들어봅시다!

오늘 배울 내용

  • ✅ React Router가 뭔가요?
  • ✅ 설치하고 기본 설정하기
  • ✅ 페이지 이동하기: Link, useNavigate
  • ✅ URL 파라미터 사용하기: useParams
  • ✅ 실전 예제: 블로그 앱 만들기

시작하기 전에

이전에 배운 내용을 기억하시나요?

오늘은 여러 페이지를 가진 웹사이트를 만드는 방법을 배워봅시다!


React Router가 뭔가요?

React Router는 React로 여러 페이지를 가진 웹사이트를 만들 때 사용하는 도구예요.

일상 비유 📖

웹사이트를 이라고 생각해보세요:

일반 웹사이트 (옛날 방식):

1
2
3
4
5
목차 페이지 → 1장 읽기
다시 목차로 돌아가서 → 2장 읽기
또 목차로 돌아가서 → 3장 읽기

매번 목차로 돌아가야 해요! (페이지 새로고침)

SPA with React Router (현대 방식):

1
2
3
4
책을 펼쳐놓고
1장 → 2장 → 3장 → 빠르게 넘기기

목차로 돌아갈 필요 없이 바로바로 이동! (새로고침 없음)

React Router를 사용하면:

  • ✅ 페이지 새로고침 없이 화면 전환
  • ✅ 빠른 페이지 이동
  • ✅ 뒤로가기/앞으로가기 버튼 작동
  • ✅ URL이 바뀌어서 북마크 가능

설치하기

터미널에서 React Router를 설치해요:

1
npm install react-router-dom

설치가 끝나면 사용 준비 완료! 🎉


기본 사용법

Step 1: BrowserRouter로 감싸기

App.js 또는 index.js에서 전체 앱을 BrowserRouter로 감싸요:

1
2
3
4
5
6
7
8
9
10
11
12
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

설명: BrowserRouter는 라우팅 기능을 활성화해주는 “감싸는 상자”예요.

Step 2: 페이지 컴포넌트 만들기

간단한 페이지 3개를 만들어봅시다:

1
2
3
4
5
6
7
8
9
10
11
// src/pages/Home.js
function Home() {
  return (
    <div style=>
      <h1>🏠 홈 페이지</h1>
      <p>React Router에 오신 것을 환영합니다!</p>
    </div>
  );
}

export default Home;
1
2
3
4
5
6
7
8
9
10
11
// src/pages/About.js
function About() {
  return (
    <div style=>
      <h1>ℹ️ 소개 페이지</h1>
      <p>이 사이트는 React Router 데모입니다.</p>
    </div>
  );
}

export default About;
1
2
3
4
5
6
7
8
9
10
11
// src/pages/Contact.js
function Contact() {
  return (
    <div style=>
      <h1>📧 연락처 페이지</h1>
      <p>이메일: contact@example.com</p>
    </div>
  );
}

export default Contact;

Step 3: Routes 설정하기

App.js에서 경로(Route)를 설정해요:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// src/App.js
import { Routes, Route, Link } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Contact from './pages/Contact';

function App() {
  return (
    <div>
      {/* 네비게이션 바 */}
      <nav style=>
        <Link to="/" style=></Link>
        <Link to="/about" style=>소개</Link>
        <Link to="/contact" style=>연락처</Link>
      </nav>

      {/* 라우트 설정 */}
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/contact" element={<Contact />} />
      </Routes>
    </div>
  );
}

export default App;

해보기:

  1. 위 코드를 복사해서 실행해보세요
  2. 네비게이션 링크를 클릭해보세요
  3. 페이지가 새로고침 없이 바뀌는지 확인하세요!

동작 원리:

  • <Route path="/" element={<Home />} />: “/” 주소일 때 Home 컴포넌트 보여주기
  • <Link to="/">: “/” 주소로 이동하는 링크 (새로고침 없음!)

❌ 일반 a 태그 (사용하지 마세요!)

1
<a href="/"></a>  // 페이지 새로고침됨!
1
<Link to="/"></Link>  // 새로고침 없음!

차이점:

  • <a> 태그: 페이지 전체가 새로고침 → 느림 😢
  • <Link>: 필요한 부분만 바뀜 → 빠름 😊

실습 1: 네비게이션 바 스타일링

좀 더 예쁜 네비게이션 바를 만들어봅시다!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import { Routes, Route, Link } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Contact from './pages/Contact';

function App() {
  return (
    <div>
      {/* 네비게이션 바 */}
      <nav style=>
        <div style=>
          <Link
            to="/"
            style=
          >
            🏠 홈
          </Link>
          <Link
            to="/about"
            style=
          >
            ℹ️ 소개
          </Link>
          <Link
            to="/contact"
            style=
          >
            📧 연락처
          </Link>
        </div>
      </nav>

      {/* 라우트 */}
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/contact" element={<Contact />} />
      </Routes>
    </div>
  );
}

export default App;

useNavigate: 프로그래밍 방식으로 이동하기

버튼을 클릭했을 때 페이지를 이동하고 싶다면? useNavigate를 사용하세요!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import { useNavigate } from 'react-router-dom';

function Home() {
  const navigate = useNavigate();

  const goToAbout = () => {
    navigate('/about');
  };

  const goBack = () => {
    navigate(-1); // 뒤로가기
  };

  return (
    <div style=>
      <h1>🏠 홈 페이지</h1>
      <p>React Router에 오신 것을 환영합니다!</p>

      <div style=>
        <button
          onClick={goToAbout}
          style=
        >
          소개 페이지로 이동
        </button>

        <button
          onClick={goBack}
          style=
        >
          뒤로가기
        </button>
      </div>
    </div>
  );
}

export default Home;

사용 예시:

  • navigate('/about') - /about 페이지로 이동
  • navigate(-1) - 뒤로가기
  • navigate(1) - 앞으로가기
  • navigate('/about', { replace: true }) - 히스토리 남기지 않고 이동

동적 라우팅: useParams

URL에 변수를 넣고 싶을 때 사용해요! 예를 들어 블로그 글마다 다른 ID를 가진 경우:

1
2
3
4
5
// App.js
<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/post/:id" element={<Post />} />
</Routes>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// pages/Post.js
import { useParams } from 'react-router-dom';

function Post() {
  const { id } = useParams(); // URL에서 id 가져오기

  // 가상의 블로그 데이터
  const posts = {
    '1': { title: 'React 입문', content: 'React를 시작해봅시다!' },
    '2': { title: 'React Router', content: 'Router로 페이지를 만들어요!' },
    '3': { title: 'Context API', content: 'Context로 상태를 관리해요!' }
  };

  const post = posts[id];

  if (!post) {
    return <div style=>존재하지 않는 글입니다.</div>;
  }

  return (
    <div style=>
      <h1>📝 {post.title}</h1>
      <p>{post.content}</p>
      <p style=>Post ID: {id}</p>
    </div>
  );
}

export default Post;

해보기:

  1. 주소창에 /post/1, /post/2, /post/3을 입력해보세요
  2. 각 ID에 맞는 내용이 표시되는지 확인하세요!

실습 2: 블로그 앱 만들기

모든 내용을 종합한 블로그 앱을 만들어봅시다!

1. 홈 페이지 (글 목록)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// pages/Home.js
import { Link } from 'react-router-dom';

function Home() {
  const posts = [
    { id: 1, title: 'React 입문', preview: 'React를 시작해봅시다!' },
    { id: 2, title: 'React Router', preview: 'Router로 페이지를 만들어요!' },
    { id: 3, title: 'Context API', preview: 'Context로 상태를 관리해요!' }
  ];

  return (
    <div style=>
      <h1>📚 블로그 글 목록</h1>

      <div style=>
        {posts.map(post => (
          <Link
            key={post.id}
            to={`/post/${post.id}`}
            style=
          >
            <div
              style=
              onMouseEnter={(e) => {
                e.currentTarget.style.backgroundColor = '#e3f2fd';
                e.currentTarget.style.borderColor = '#2196f3';
              }}
              onMouseLeave={(e) => {
                e.currentTarget.style.backgroundColor = '#f5f5f5';
                e.currentTarget.style.borderColor = '#e0e0e0';
              }}
            >
              <h2 style=>{post.title}</h2>
              <p style=>{post.preview}</p>
            </div>
          </Link>
        ))}
      </div>
    </div>
  );
}

export default Home;

2. 글 상세 페이지

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// pages/Post.js
import { useParams, useNavigate } from 'react-router-dom';

function Post() {
  const { id } = useParams();
  const navigate = useNavigate();

  const posts = {
    '1': {
      title: 'React 입문',
      content: 'React는 Facebook에서 만든 JavaScript 라이브러리입니다. 컴포넌트 기반으로 UI를 구성하며, Virtual DOM을 사용해 효율적인 렌더링이 가능합니다.',
      date: '2025-01-01'
    },
    '2': {
      title: 'React Router',
      content: 'React Router는 SPA(Single Page Application)를 만들 때 사용하는 라이브러리입니다. 페이지 새로고침 없이 URL을 변경하고 컴포넌트를 렌더링할 수 있습니다.',
      date: '2025-01-02'
    },
    '3': {
      title: 'Context API',
      content: 'Context API는 Props Drilling 문제를 해결하기 위한 React의 기능입니다. 전역 상태를 관리하고, 깊이 중첩된 컴포넌트에 데이터를 쉽게 전달할 수 있습니다.',
      date: '2025-01-03'
    }
  };

  const post = posts[id];

  if (!post) {
    return (
      <div style=>
        <h1>😢 존재하지 않는 글입니다</h1>
        <button
          onClick={() => navigate('/')}
          style=
        >
          홈으로 돌아가기
        </button>
      </div>
    );
  }

  return (
    <div style=>
      <button
        onClick={() => navigate('/')}
        style=
      >
        ← 목록으로
      </button>

      <article>
        <h1 style=>
          📝 {post.title}
        </h1>
        <p style=>
          {post.date}
        </p>
        <div style=>
          {post.content}
        </div>
      </article>

      <div style=>
        <p style=>
          💡 이 글이 도움이 되셨나요?
        </p>
        <p style=>
          다른 글도 확인해보세요!
        </p>
      </div>
    </div>
  );
}

export default Post;

3. 전체 App 구성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// App.js
import { Routes, Route, Link } from 'react-router-dom';
import Home from './pages/Home';
import Post from './pages/Post';
import About from './pages/About';

function App() {
  return (
    <div>
      {/* 네비게이션 */}
      <nav style=>
        <div style=>
          <Link
            to="/"
            style=
          >
            📚 My Blog
          </Link>
          <div style=>
            <Link
              to="/"
              style=
            ></Link>
            <Link
              to="/about"
              style=
            >
              소개
            </Link>
          </div>
        </div>
      </nav>

      {/* 라우트 */}
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/post/:id" element={<Post />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </div>
  );
}

export default App;

해보기:

  1. 홈 페이지에서 글 카드를 클릭해보세요
  2. 글 상세 페이지에서 “목록으로” 버튼을 클릭해보세요
  3. 주소창의 URL이 바뀌는 것을 확인하세요
  4. 브라우저의 뒤로가기 버튼도 작동하는지 확인하세요!

404 페이지 만들기

존재하지 않는 URL에 접근했을 때 보여줄 페이지를 만들어봅시다:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// pages/NotFound.js
import { useNavigate } from 'react-router-dom';

function NotFound() {
  const navigate = useNavigate();

  return (
    <div style=>
      <h1 style=>404</h1>
      <h2 style=>
        페이지를 찾을 수 없습니다
      </h2>
      <p style=>
        요청하신 페이지가 존재하지 않습니다.
      </p>
      <button
        onClick={() => navigate('/')}
        style=
      >
        홈으로 돌아가기
      </button>
    </div>
  );
}

export default NotFound;
1
2
3
4
5
6
7
// App.js에 추가
<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/post/:id" element={<Post />} />
  <Route path="/about" element={<About />} />
  <Route path="*" element={<NotFound />} />  {/* 모든 잘못된 경로 */}
</Routes>

흔한 실수와 해결 방법

실수 1: BrowserRouter로 감싸지 않음

잘못된 코드:

1
2
// index.js
root.render(<App />);  // BrowserRouter 없음!

⚠️ 에러: “useNavigate() may be used only in the context of a Router component”

올바른 코드:

1
2
3
4
5
6
// index.js
root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

실수 2: a 태그 사용

잘못된 코드:

1
<a href="/about">소개</a>  // 페이지 새로고침됨!

올바른 코드:

1
<Link to="/about">소개</Link>  // 새로고침 없음!

실수 3: Routes 안에 Route가 아닌 다른 요소

잘못된 코드:

1
2
3
4
<Routes>
  <div>헤더</div>  // Routes 안에는 Route만!
  <Route path="/" element={<Home />} />
</Routes>

올바른 코드:

1
2
3
4
<div>헤더</div>  {/* Routes 밖에 */}
<Routes>
  <Route path="/" element={<Home />} />
</Routes>

정리

오늘은 React Router로 여러 페이지를 가진 앱을 만드는 방법을 배웠어요!

핵심 포인트 ✅

기본 개념:

  • React Router: 페이지 새로고침 없이 화면 전환
  • SPA (Single Page Application): 하나의 페이지에서 모든 것을 처리

핵심 컴포넌트:

  • <BrowserRouter>: 라우팅 기능 활성화
  • <Routes>: 라우트 목록을 감싸는 컨테이너
  • <Route>: 경로와 컴포넌트 연결
  • <Link>: 페이지 이동 링크 (새로고침 없음)

핵심 Hooks:

  • useNavigate(): 프로그래밍 방식으로 페이지 이동
  • useParams(): URL 파라미터 가져오기

오늘 배운 내용 체크 ✅

  • React Router가 무엇인지 이해했나요?
  • BrowserRouter로 앱을 감쌌나요?
  • Link로 페이지 이동을 구현했나요?
  • useNavigate로 버튼 클릭 시 이동을 구현했나요?
  • useParams로 동적 라우팅을 구현했나요?
  • 404 페이지를 만들어봤나요?

숙제 📚

  1. 프로필 페이지 추가: /profile/:username 경로 만들기
  2. 검색 페이지: 검색어를 URL에 포함시키기
  3. 카테고리별 필터링: /category/:name 경로로 카테고리별 글 표시

다음 단계

다음 포스트에서는 폼 처리와 유효성 검증을 배워봅니다! 사용자 입력을 받고, 검증하고, 제출하는 방법을 알아봐요.

“늦었다고 생각할 때가 가장 빠를 때입니다. React Router 마스터! 🎉”


React 완벽 가이드 시리즈

  1. React란 무엇인가?
  2. 첫 React 앱 만들기
  3. useState - 클릭하면 바뀌는 화면
  4. Props - 컴포넌트끼리 대화하기
  5. useEffect - 컴포넌트 생명주기
  6. 조건부/리스트 렌더링
  7. Context API - Props 지옥에서 탈출
  8. Custom Hooks - 반복되는 로직 재사용하기
  9. React Router - 페이지 이동하기 ← 현재 글
  10. 폼 처리와 유효성 검증
  11. React 성능 최적화
  12. 에러 바운더리와 Suspense
  13. 상태 관리 라이브러리
  14. 서버 상태 관리
  15. React와 TypeScript
  16. Next.js 입문
  17. React 테스팅 전략
  18. 고급 패턴과 베스트 프랙티스
  19. 실전 프로젝트
  20. React 배포와 DevOps

관련 자료

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.