☁️ goormTIL | React #29

매루·2025년 10월 21일

goormTIL

목록 보기
27/67
post-thumbnail

📅 2025-10-21

➡️ React Router DOM에 대해 새롭게 알게 된 것 또는 헷갈리는 부분 정리


🔎 학습 리마인드

📌 Dynamic Route

  • Dynamic Route(동적 라우트)는 URL 경로에 유동적인 값(파라미터)을 포함시켜 하나의 컴포넌트로 여러 개의 세부 페이지를 표현할 수 있도록 하는 라우팅 방식

라우트 설정

// src/Router.js
import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "../pages/Home";
import About from "../pages/About";
import Contact from "../pages/Contact";
import Works from "../pages/Works";

const Router = () => {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="about" element={<About />} />
        <Route path="contact" element={<Contact />} />
        <Route path="works" element={<Works />} />
        {/* 동적 라우트 추가 */}
        <Route path="works/:id" element={<Works />} />
      </Routes>
    </BrowserRouter>
  );
};

export default Router;
  • /works/1, /works/2, /works/3 … 처럼 각 work가 개별 페이지를 가질 때, 모든 경로를 하나하나 지정하는 대신 동적 경로(:id)로 한 번에 처리할 수 있음
  • :id → URL의 가변적인 부분을 의미하는 파라미터 변수

💡 useParams

  • 동적 경로에 지정한 :id 값은 useParams() 훅을 사용해 조회 가능
    import React from 'react';
    import { useParams } from 'react-router-dom';
    
    const data = [
      { id: 1, todo: '리액트 배우기' },
      { id: 2, todo: 'supabase 배우기' },
      { id: 3, todo: '자바스크립트 배우기' },
      { id: 4, todo: 'DB 배우기' },
      { id: 5, todo: '넥스트 배우기' },
      { id: 6, todo: 'HTTP 프로토콜 배우기' },
    ];
    
    function Work() {
      const param = useParams();
    
      const work = data.find((work) => work.id === parseInt(param.id));
    
      return <div>{work.todo}</div>;
    }
    
    export default Work;
    • 페이지별 고유 데이터 구분

💡 useSearchParams

  • useSearchParams현재 URL의 쿼리스트링(query string)을 읽고 수정할 수 있는 훅
  • 주소창의 ?key=value 형태 데이터를 상태처럼 관리할 수 있게 해줌
    import { useSearchParams } from "react-router-dom";
    
    function Works() {
       const [searchParams, setSearchParams] = useSearchParams();
    
      const keyword = searchParams.get("keyword"); // 쿼리값 읽기
    
      const handleChange = (e) => {
        // 입력할 때마다 URL 쿼리 갱신
        setSearchParams({ keyword: e.target.value });
      };
    
      return (
        <div>
          <input value={keyword || ""} onChange={handleChange} />
          <p>검색어: {keyword}</p>
        </div>
      );
    }
    • keyword=리액트/works?keyword=리액트 형태로 주소창에 표시

💡 주요 메서드 정리

메서드설명
searchParams.get(key)특정 key의 첫 번째 value 반환
searchParams.getAll(key)특정 key의 모든 value를 배열로 반환
searchParams.set(key, value)인자로 전달한 key 값을 value로 설정 (기존 값 덮어씀)
searchParams.append(key, value)기존 값을 유지하고 새 값을 추가

📌 중첩 라우트 (Outlet)

  • 중첩 라우팅은 특정 라우트 내에서 추가적인 라우트를 정의하는 방식. 여러 개의 계층의 UI를 구성할 때 유용하게 사용
    import { BrowserRouter, Routes, Route } from 'react-router-dom';
    import DashboardLayout from './DashboardLayout';
    import Profile from './Profile';
    import Settings from './Settings';
    import Reports from './Reports';
    
    function App() {
      return (
        <BrowserRouter>
          <Routes>
            <Route path="/dashboard" element={<DashboardLayout />}>
              <Route index element={<Profile />} />
              <Route path="settings" element={<Settings />} />
              <Route path="reports" element={<Reports />} />
            </Route>
          </Routes>
        </BrowserRouter>
      );
    }
    • /dashboardDashboardLayout 렌더링
    • /dashboard/settings, /dashboard/reports → 같은 레이아웃을 공유하면서 내부 내용만 변경

💡 Outlet 컴포넌트

  • Outlet은 부모 라우트 내에서 자식 라우트가 렌더링될 위치를 지정
    import { Outlet } from 'react-router-dom';
    
    function DashboardLayout() {
      return (
        <div>
          <header>Header Section</header>
          <main>
            {/* 자식 라우트가 렌더링되는 위치 */}
            <Outlet />
          </main>
          <footer>Footer Section</footer>
        </div>
      );
    }

💡 중첩 라우팅 vs children 공통 컴포넌트

구분중첩 라우팅공통 레이아웃
구조<Route> 내부에 <Route> 정의라우트 외부에서 <Layout>으로 감싸기
렌더링 위치<Outlet />에 하위 라우트 렌더링<Layout> 내의 <Routes>에 페이지 표시
장점계층적이고 동적 관리에 유리단순하고 일관된 구조 유지에 유리

중첩 라우팅

<Routes>
  <Route path="/" element={<Layout />}>
    <Route index element={<Home />} />
    <Route path="about" element={<About />} />
  </Route>
</Routes>

공통 레이아웃

<Layout>
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path="about" element={<About />} />
  </Routes>
</Layout>

📌 ProtectedRoute (접근 보호 라우트)

  • 로그인 하지 않는 사용자가 보호된 페이지에 접근하려고 할 때, 로그인 페이지 우회시키는 패턴

언제 사용하나?

  • 인증 필요한 페이지
  • 이메일/권한 확인 전 단계 차단
  • 권한 기반 접근( 관리자 / 일반 사용자 ) 분기
import { Navigate } from "react-router-dom";

// 문지기 역할 컴포넌트
function ProtectedRoute({ isAllowed, children }) {
  if (!isAllowed) {
    // 조건을 만족하지 않으면 Home으로 돌려보냄
    return <Navigate to="/" replace />;
  }
  return children;
}
// Router.jsx
import ProtectedRoute from "./ProtectedRoute";
import MyPage from "./MyPage";

<Route
  path="mypage"
  element={
    <ProtectedRoute isAllowed={false}>
      <MyPage />
    </ProtectedRoute>
  }
/>
  • isAllowedfalse/mypage를 직접 주소창에 쳐도 Home으로 돌려보냅니다.

💡 Navigate를 이용한 리다이렉션

  • Navigate는 런더링 이후에 조건을 확인하고, 상황에 따라 페이지 이동
  • 컴포넌트 내부에서 조건부로 이동을 처리할 때 사용
    import { Navigate } from "react-router-dom";
    
    const Mypage = () => {
      const isLogin = false;
    
      if (!isLogin) {
        return <Navigate to="/login" replace />;
      }
    
      return <h2>마이페이지</h2>;
    };

0개의 댓글