GDGoC/FrontEnd

[Frontend] #05. React - React Router와 전역 상태 관리

Opal1031 2026. 5. 6. 16:25

React Router와 전역 상태 관리

React Router를 사용하여 SPA를 구현하고, useContext로 전역 상태를 관리할 수 있다.


1️⃣ React Router

  • React는 SPA(Single Page Application) 방식으로 동작한다.
  • SPA는 하나의 HTML 파일로 여러 화면을 구현하기 때문에, URL과 화면을 연결하는 라우팅 관리가 필요하다.
  • React Router는 URL 경로에 따라 적절한 컴포넌트를 렌더링해주는 도구다.
  • 페이지 새로고침 없이 화면을 전환할 수 있다.

 

설치

npm install react-router-dom

 

기본 설정

import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="*" element={<div>404 Not Found</div>} />
      </Routes>
    </BrowserRouter>
  );
}

export default App;

 

요소 역할
<BrowserRouter> 앱 전체에 라우팅 기능 제공
<Routes> 라우트 목록을 감싸는 컨테이너
<Route> URL 경로와 컴포넌트를 연결
path="*" 정의되지 않은 경로 처리 (404)

2️⃣ 페이지 이동 방법

1. Link 컴포넌트

  • 클릭 가능한 링크를 만들 때 사용
  • HTML의 <a> 태그와 비슷하지만, 페이지 새로고침이 발생하지 않는다.
import { Link } from 'react-router-dom';

function Nav() {
  return (
    <nav>
      <Link to="/">홈</Link>
      <span> | </span>
      <Link to="/about">소개</Link>
    </nav>
  );
}

 

2. useNavigate Hook

  • 조건부 이동이나 이벤트 기반 이동에 사용
  • 로그인 성공 후 자동으로 페이지 이동하는 경우 등에 유용
import { useNavigate } from 'react-router-dom';

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

  const handleLogin = () => {
    // 로그인 로직...
    navigate('/home'); // 로그인 성공 후 홈으로 이동
  };

  return <button onClick={handleLogin}>로그인</button>;
}

 

비교

Link useNavigate
형태 JSX 태그 함수
사용처 클릭 가능한 링크 조건부/이벤트 기반 이동
예시 <Link to="/about">소개</Link> navigate('/about')

3️⃣ 컴포넌트 구조화

  • 화면을 작은 단위로 분리하여 재사용성유지보수성을 높인다.
  • 공통 레이아웃(Header, Footer 등)을 별도 컴포넌트로 분리한다.
function Header() {
  return <header>나의 React 앱</header>;
}

function Footer() {
  return <footer>© 2025</footer>;
}

function AppShell({ children }) {
  return (
    <>
      <Header />
      {children}
      <Footer />
    </>
  );
}

 

Router와 결합

import { BrowserRouter, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <AppShell>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
        </Routes>
      </AppShell>
    </BrowserRouter>
  );
}

4️⃣ 폴더 구조 설계

기본 구조

src/
├── components/      # 공통 UI 컴포넌트
│   ├── Header.jsx
│   └── Footer.jsx
├── pages/           # 페이지 컴포넌트
│   ├── Home.jsx
│   └── About.jsx
├── contexts/        # 전역 상태 관리
│   └── ThemeContext.jsx
└── App.jsx          # 라우팅 설정

 

대규모 프로젝트 구조

src/
├── features/        # 기능별 폴더
│   ├── auth/
│   │   ├── pages/
│   │   ├── components/
│   │   └── services/  # API 통신
└── shared/          # 공용 컴포넌트

5️⃣ useContext (전역 상태 관리)

  • 컴포넌트 깊이가 깊어질수록 같은 데이터를 여러 단계에 걸쳐 전달해야 하는 Props Drilling 문제가 발생한다.
  • useContext를 사용하면 상위에서 제공한 값을 하위 어디서나 직접 꺼내 쓸 수 있다.
  • 여러 컴포넌트에서 공통적으로 사용해야 하는 데이터(테마, 로그인 정보 등)를 관리할 때 유용하다.

 

Context 생성 (contexts/ThemeContext.jsx)

import { createContext, useContext, useState } from 'react';

const ThemeContext = createContext(null);

export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
  const value = { theme, setTheme };

  return (
    <ThemeContext.Provider value={value}>
      {children}
    </ThemeContext.Provider>
  );
}

export function useTheme() {
  return useContext(ThemeContext);
}

 

Context 사용 (components/Header.jsx)

import { Link } from 'react-router-dom';
import { useTheme } from '../contexts/ThemeContext';

function Header() {
  const { theme, setTheme } = useTheme();
  const nextTheme = theme === 'light' ? 'dark' : 'light';

  return (
    <header style={{
      background: theme === 'light' ? '#f9f9f9' : '#1a1a1a',
      color: theme === 'light' ? '#111' : '#f0f0f0',
      padding: '12px 16px'
    }}>
      <nav>
        <Link to="/">홈</Link> | <Link to="/about">소개</Link>
      </nav>
      <div>
        <span>현재 테마: {theme}</span>
        <button onClick={() => setTheme(nextTheme)}>테마 전환</button>
      </div>
    </header>
  );
}

export default Header;

 

App에서 Provider로 감싸기

import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { ThemeProvider } from './contexts/ThemeContext';
import Header from './components/Header';
import Home from './pages/Home';
import About from './pages/About';

function App() {
  return (
    <ThemeProvider>
      <BrowserRouter>
        <Header />
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
          <Route path="*" element={<div>404 Not Found</div>} />
        </Routes>
      </BrowserRouter>
    </ThemeProvider>
  );
}

export default App;

 

페이지 컴포넌트에서 Context 사용 (pages/Home.jsx)

import { useTheme } from '../contexts/ThemeContext';

function Home() {
  const { theme } = useTheme();

  const style = {
    padding: 24,
    minHeight: '100vh',
    background: theme === 'light' ? '#ffffff' : '#111111',
    color: theme === 'light' ? '#111111' : '#f5f5f5'
  };

  return (
    <main style={style}>
      <h1>홈</h1>
      <p>React Router로 연결된 홈 화면입니다.</p>
      <p>헤더의 테마 전환 버튼으로 전역 상태를 변경할 수 있습니다.</p>
    </main>
  );
}

export default Home;

useContext 사용 시 주의사항

  • 너무 많은 값을 한 Context에 넣지 말 것: 하위 컴포넌트 전체가 불필요하게 리렌더링될 수 있다.
  • 변경 빈도에 따라 Context 분리: 자주 변경되는 값과 그렇지 않은 값을 별도 Context로 관리한다.
  • 적절한 사용처: 테마, 로그인 정보, 언어 설정 등 전역적으로 필요한 데이터에 적합하다.
  • 성능 최적화: useMemo를 활용하여 Context value 객체를 메모이제이션할 수 있다.
import { useMemo } from 'react';

export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');
  const value = useMemo(() => ({ theme, setTheme }), [theme]);

  return (
    <ThemeContext.Provider value={value}>
      {children}
    </ThemeContext.Provider>
  );
}

'GDGoC > FrontEnd' 카테고리의 다른 글

[Frontend] #06. React - 비동기 통신  (0) 2026.05.06
[Frontend] #04. React - State와 Hooks  (0) 2026.05.06
[Frontend] #03. React 기초  (0) 2026.05.06
[Frontend] #02. JavaScript  (0) 2026.05.06
[Frontend] #01. HTML / CSS  (0) 2026.05.06