React Router로 감정 일기장 SPA 구현: 동적 라우팅·useParams·Link 실습 가이드

1편에서 React 프로젝트를 만들고 기본 구조를 이해했어요. 이제 본격적으로 여러 페이지를 만들어볼 차례예요!

일반 웹사이트처럼 /home, /diary, /new 이런 URL로 다른 화면을 보여주려면 React Router가 필요해요. 오늘은 이걸 사용해서 4개의 페이지를 만들고 연결하는 방법을 배워봅시다.

이번 편에서 배울 내용

  • ✅ App.js의 역할 (교통 정리하기)
  • ✅ Routes와 Route 컴포넌트 사용법
  • ✅ Home, New, Diary, Edit 페이지 생성
  • ✅ Link 컴포넌트로 페이지 이동하기
  • ✅ 동적 라우팅 (:id 파라미터) 이해하기

전체 구조 먼저 보기

오늘 만들 구조를 다이어그램으로 먼저 볼게요:

graph TD
    A["index.html<br/>(빈 HTML 파일)"] --> B["index.js<br/>(React 앱 시작점)"]
    B --> C["App.js<br/>(라우터 - 교통정리)"]
    
    C --> D["Home 페이지<br/>(/)"]
    C --> E["New 페이지<br/>(/new)"]
    C --> F["Diary 페이지<br/>(/diary/:id)"]
    C --> G["Edit 페이지<br/>(/edit/:id)"]
    
    style A fill:#e1f5ff
    style B fill:#ffe1e1
    style C fill:#fff4e1
    style D fill:#e1ffe1
    style E fill:#e1ffe1
    style F fill:#e1ffe1
    style G fill:#e1ffe1

App.js가 교통경찰처럼 “이 URL로 오면 이 페이지 보여줘!” 하고 정리하는 거예요.

페이지 파일 만들기

먼저 페이지 파일들을 만들어야 해요. 터미널에서 이 명령어들을 실행하세요:

# src/page 폴더 생성
mkdir src/page

# 윈도우 사용자는 이렇게
# mkdir src\page

이제 VS Code에서 src/page 폴더 안에 4개의 파일을 만들어주세요:

1. Home.js - 메인 페이지

const Home = () => {
    return (
        <div>
            <h1>Home 페이지</h1>
            <p>감정 일기장 메인 페이지입니다.</p>
        </div>
    );
};

export default Home;

2. New.js - 새 일기 작성 페이지

const New = () => {
    return (
        <div>
            <h1>New 페이지</h1>
            <p>새로운 일기를 작성하는 페이지입니다.</p>
        </div>
    );
};

export default New;

3. Diary.js - 일기 상세보기 페이지

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

const Diary = () => {
    const { id } = useParams();
    
    return (
        <div>
            <h1>Diary 페이지</h1>
            <p>{id}번 일기를 보고 있습니다.</p>
        </div>
    );
};

export default Diary;

4. Edit.js - 일기 수정 페이지

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

const Edit = () => {
    const { id } = useParams();
    
    return (
        <div>
            <h1>Edit 페이지</h1>
            <p>{id}번 일기를 수정하는 페이지입니다.</p>
        </div>
    );
};

export default Edit;

useParams()가 뭔지 궁금하시죠? URL에서 :id 부분의 값을 가져오는 React Router의 훅이에요. 나중에 자세히 설명할게요!

App.js에 라우터 설정하기

이제 src/App.js를 열어서 라우터를 설정해볼게요. 기존 코드를 전부 지우고 이렇게 작성하세요:

import { Routes, Route } from 'react-router-dom';
import Home from './page/Home';
import New from './page/New';
import Diary from './page/Diary';
import Edit from './page/Edit';
import './App.css';

function App() {
  return (
    <div className="App">
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/new" element={<New />} />
        <Route path="/diary/:id" element={<Diary />} />
        <Route path="/edit/:id" element={<Edit />} />
      </Routes>
    </div>
  );
}

export default App;

코드를 하나씩 뜯어볼게요:

Import 부분

import { Routes, Route } from 'react-router-dom';
  • Routes: 여러 개의 Route를 묶어주는 컨테이너
  • Route: 개별 경로와 컴포넌트를 연결
import Home from './page/Home';
import New from './page/New';
import Diary from './page/Diary';
import Edit from './page/Edit';

방금 만든 4개의 페이지를 불러와요.

Routes와 Route 사용하기

<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/new" element={<New />} />
  <Route path="/diary/:id" element={<Diary />} />
  <Route path="/edit/:id" element={<Edit />} />
</Routes>

이게 핵심이에요! 표로 정리하면:

URL 주소보여줄 페이지설명
/Home메인 페이지
/newNew새 일기 작성
/diary/:idDiary일기 상세보기 (예: /diary/1, /diary/123)
/edit/:idEdit일기 수정 (예: /edit/1, /edit/123)

:id 부분이 재밌는데요, 이건 “여기에 아무 값이나 들어올 수 있어”라는 뜻이에요.

예를 들어:

  • /diary/1 → Diary 페이지 (id=1)
  • /diary/123 → Diary 페이지 (id=123)
  • /diary/abc → Diary 페이지 (id=abc)

다 같은 Diary 페이지로 가지만, id 값은 다르죠. 이 값을 useParams()로 가져와서 “몇 번 일기를 보는지” 알 수 있어요.

페이지 이동 버튼 만들기

이제 브라우저 주소창에 직접 URL을 치지 않고도 페이지를 이동할 수 있게 네비게이션 버튼을 만들어볼게요.

App.js에 Link 버튼들을 추가하세요:

import { Routes, Route, Link } from 'react-router-dom';  // Link 추가!
import Home from './page/Home';
import New from './page/New';
import Diary from './page/Diary';
import Edit from './page/Edit';
import './App.css';

function App() {
  return (
    <div className="App">
      {/* 네비게이션 메뉴 추가 */}
      <nav style={{ 
        padding: '20px', 
        borderBottom: '2px solid #ccc',
        marginBottom: '20px'
      }}>
        <Link to="/" style={{ marginRight: '10px' }}>Home</Link>
        <Link to="/new" style={{ marginRight: '10px' }}>New</Link>
        <Link to="/diary/1" style={{ marginRight: '10px' }}>Diary(1번)</Link>
        <Link to="/edit/1">Edit(1번)</Link>
      </nav>

      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/new" element={<New />} />
        <Route path="/diary/:id" element={<Diary />} />
        <Route path="/edit/:id" element={<Edit />} />
      </Routes>
    </div>
  );
}

export default App;

파일을 저장하고 브라우저를 보세요. 상단에 4개의 링크가 보이죠?

이제 링크를 클릭하면 페이지가 전환돼요! 🎉

“그냥 <a href="/"> 쓰면 안 돼요?” 하고 물어볼 수 있어요.

차이점을 볼게요:

// ❌ 이렇게 쓰면 안 돼요
<a href="/">Home</a>  // 페이지 전체를 새로고침함

// ✅ 이렇게 써야 해요
<Link to="/">Home</Link>  // 필요한 부분만 바꿔서 빠름

<a> 태그를 쓰면 페이지를 통째로 새로고침해요. 그러면 React 앱이 처음부터 다시 시작돼서 느려요.

<Link>는 필요한 컴포넌트만 바꿔서 훨씬 빠르고 부드럽게 전환돼요. 이게 바로 **SPA(Single Page Application)**의 장점이에요!

동적 라우팅 자세히 알아보기

아까 useParams()를 썼죠? 이걸 좀 더 자세히 봅시다.

Diary.js에서 ID 사용하기

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

const Diary = () => {
    const { id } = useParams();
    
    return (
        <div>
            <h1>Diary 페이지</h1>
            <p>{id}번 일기를 보고 있습니다.</p>
            
            {/* 실제로는 이 id로 데이터베이스에서 일기를 가져와요 */}
            <div style={{ 
                padding: '20px', 
                backgroundColor: '#f0f0f0',
                borderRadius: '8px',
                marginTop: '20px'
            }}>
                <h3>일기 내용 (예시)</h3>
                <p>오늘은 날씨가 좋았다. 기분이 좋아서 산책을 했다...</p>
                <p><small>작성일: 2024-12-{id}일</small></p>
            </div>
        </div>
    );
};

export default Diary;

이제 다른 번호로 테스트해볼까요? 브라우저 주소창에:

  • http://localhost:3000/diary/1 입력 → “1번 일기”
  • http://localhost:3000/diary/999 입력 → “999번 일기”

번호가 바뀌는 게 보이죠?

여러 개의 파라미터

나중에 이런 것도 가능해요:

<Route path="/diary/:year/:month/:id" element={<Diary />} />
const Diary = () => {
    const { year, month, id } = useParams();
    
    return (
        <div>
            <h1>{year}년 {month}월의 {id}번 일기</h1>
        </div>
    );
};

URL: /diary/2024/12/5 → “2024년 12월의 5번 일기”

뒤로가기 버튼 만들기

페이지에 뒤로가기 버튼도 추가해볼게요. Diary.js를 수정하세요:

import { useParams, useNavigate } from 'react-router-dom';

const Diary = () => {
    const { id } = useParams();
    const navigate = useNavigate();
    
    const handleGoBack = () => {
        navigate(-1);  // 이전 페이지로!
    };
    
    const handleGoHome = () => {
        navigate('/');  // 홈으로!
    };
    
    return (
        <div>
            <h1>Diary 페이지</h1>
            <p>{id}번 일기를 보고 있습니다.</p>
            
            <div style={{ marginTop: '20px' }}>
                <button onClick={handleGoBack} style={{ marginRight: '10px' }}>
                    뒤로가기
                </button>
                <button onClick={handleGoHome}>
                    홈으로
                </button>
            </div>
        </div>
    );
};

export default Diary;
  • navigate(-1): 브라우저의 뒤로가기 버튼과 똑같아요
  • navigate('/'): 특정 경로로 이동해요
  • navigate(-2): 두 페이지 뒤로 가요

확인하기

여기까지 잘 따라오셨나요? 다음 항목들을 확인해보세요:

페이지 생성 확인

  • src/page 폴더에 4개의 파일 (Home.js, New.js, Diary.js, Edit.js) 생성됨

라우팅 동작 확인

  • / 접속 시 Home 페이지 표시
  • /new 접속 시 New 페이지 표시
  • /diary/1 접속 시 Diary 페이지에 “1번 일기” 표시
  • /edit/1 접속 시 Edit 페이지에 “1번 일기” 표시

네비게이션 확인

  • 상단 링크 클릭 시 페이지 전환됨
  • 페이지 새로고침 없이 부드럽게 전환됨
  • 브라우저 뒤로가기/앞으로가기 버튼 정상 동작

동적 라우팅 확인

  • /diary/1, /diary/2, /diary/999 모두 같은 페이지로 이동
  • 각각 다른 ID 값이 표시됨

자주 묻는 질문

Q1. Route 순서가 중요한가요?

네, 때로는 중요해요! React Router는 위에서 아래로 순서대로 매칭을 시도해요.

// ❌ 이렇게 하면 안 돼요
<Route path="/diary/:id" element={<Diary />} />
<Route path="/diary/new" element={<DiaryNew />} />

// "/diary/new"를 입력하면 첫 번째 Route에 매칭돼서
// Diary 컴포넌트가 나타나고 id="new"가 돼요
// ✅ 이렇게 해야 해요
<Route path="/diary/new" element={<DiaryNew />} />
<Route path="/diary/:id" element={<Diary />} />

// 구체적인 경로를 먼저 쓰세요!

Q2. 404 페이지는 어떻게 만들어요?

이렇게 하면 돼요:

<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/new" element={<New />} />
  <Route path="/diary/:id" element={<Diary />} />
  <Route path="/edit/:id" element={<Edit />} />
  <Route path="*" element={<NotFound />} />  {/* 404 페이지 */}
</Routes>

path="*"는 “위의 모든 경로와 일치하지 않으면” 이라는 뜻이에요.

네! useNavigate를 쓰면 돼요:

const navigate = useNavigate();

const handleSubmit = () => {
    // 일기 저장 로직...
    navigate('/');  // 저장 후 홈으로 이동
};

폼을 제출하거나 로그인 후 리다이렉트할 때 유용해요.

Q4. URL 파라미터 외에 데이터를 전달하려면?

state를 사용할 수 있어요:

// 데이터와 함께 이동
navigate('/diary/1', { state: { emotion: '행복' } });

// 받는 쪽
const location = useLocation();
console.log(location.state.emotion);  // "행복"

정리하며

오늘 2편에서 배운 내용을 정리하면:

핵심만 기억하세요:

  1. 🚦 App.js가 교통경찰 역할 (Routes와 Route로 URL 매칭)
  2. 🔗 Link로 페이지 이동 (<a>보다 빠름)
  3. 📍 :id는 동적 파라미터 (useParams로 가져옴)
  4. ⬅️ navigate로 프로그래밍 방식 이동 가능

다음 편에서는 본격적으로 Editor 컴포넌트를 만들면서 State 관리를 배워볼 거예요. 사용자가 입력하는 날짜, 감정, 일기 내용을 어떻게 저장하고 관리하는지 알아봅시다!


시리즈 네비게이션


댓글 남기기

궁금한 점이나 나누고 싶은 이야기가 있다면 자유롭게 남겨주세요.
여러분의 소중한 의견이 블로그를 성장시킵니다! 🌱

💡 오늘의 명언

"꽃은 자신을 누구와 비교하지 않는다. 그저 피어날 뿐이다."

✍️ 작성하기

💬0개의 댓글

댓글을 불러오는 중입니다...