생활코딩! React 리액트 프로그래밍

egoing - React Router DOM - stackblitz ver

lshjju 2025. 9. 5. 13:33

React Router DOM

https://lshjju.tistory.com/135

 

React.js Router DOM - 리액트 라우터 돔

React Router DOM의 주요 기능 React는 '단일 페이지 애플리케이션(SPA)'을 만드는 데 주로 사용됩니다. SPA는 기본적으로 HTML 파일 하나만을 로드한 뒤, JavaScript를 통해 화면의 내용을 동적으로 바꾸는

lshjju.tistory.com



Final Build 

https://stackblitz.com/edit/vitejs-vite-9fbg1z36?file=src%2Fmain.jsx

 

egoing - React Router DOM - StackBlitz

Next generation frontend tooling. It's fast!

stackblitz.com



New project building

여러가지 이슈로 스택블리츠에서 프로젝트를 진행하겠습니다.

 

https://lshjju.tistory.com/104

 

StackBlitz web editor - 스택블리츠 웹 에디터

스택블리츠로 새 프로젝트 생성하기 https://stackblitz.com/ 로그인 방법 선택 대쉬보드에서 new project + 버튼 - 탭 모달 - frontend 탭 - 탭react javascript - 탭 바이트 리액트가 생성됩니다.프로젝트 생성 완

lshjju.tistory.com



컴포넌트 3개 만듭니다.


 

import App from "./App"; //삭제

 

main.jsx

 

앞으로 특별한 안내가 없으면 main.jsx에서 코딩 합니다.

이 프로젝트에서는 App.jsx 를 사용하지 않습니다.

main.jsx에서 펑션앱을 직접 코딩합니다.

위 코드는 삭제합니다.


function App() {
  return (
    <div>Hello React Router DOM</div>
  );
}

 

펑션앱을 임포트 아래 추가합니다.


function Home() {
  return (
    <div>
      <h2>Home</h2>
      Home...
    </div>
  );
}

function Topics() {
  return (
    <div>
      <h2>Topics</h2>
      Topics...
    </div>
  );
}
  
function Contact() {
  return (
    <div>
      <h2>Contact</h2>
      Contact...
    </div>
  );
}

function App() {
  return (
    <div>
      <h1>Hello React Router DOM</h1>
      <Home></Home>
      <Topics></Topics>
      <Contact></Contact>
    </div>
  );
}

 

컴포넌트 3개 빌딩 합니다.

펑션앱에 컴포넌트 추가 합니다.


/* null */

index.css

 

css 코드는 모두 삭제해도 좋습니다.


test

 


Completion

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';

function Home() {
  return (
    <div>
      <h2>Home</h2>
      Home...
    </div>
  );
}

function Topics() {
  return (
    <div>
      <h2>Topics</h2>
      Topics...
    </div>
  );
}

function Contact() {
  return (
    <div>
      <h2>Contact</h2>
      Contact...
    </div>
  );
}

function App() {
  return (
    <div>
      <h1>Hello React Router DOM</h1>
      <Home></Home>
      <Topics></Topics>
      <Contact></Contact>
    </div>
  );
}

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <App />
  </StrictMode>
);

Comment ver

// React의 StrictMode를 import 합니다. 이는 애플리케이션 내의 잠재적인 문제들을 식별하는 데 도움을 줍니다.
import { StrictMode } from 'react';
// React 18에서 도입된 새로운 루트 API인 createRoot를 import 합니다.
// 이를 통해 React 요소를 DOM 컨테이너 내부에 렌더링할 수 있습니다.
import { createRoot } from 'react-dom/client';
// 애플리케이션의 전역 스타일을 정의하는 CSS 파일을 import 합니다.
import './index.css';

/**
 * Home 섹션을 렌더링하는 함수 컴포넌트입니다.
 * @returns {JSX.Element} Home 섹션의 UI를 포함하는 JSX 요소
 */
function Home() {
  return (
    <div>
      <h2>Home</h2>
      Home...
    </div>
  );
}

/**
 * Topics 섹션을 렌더링하는 함수 컴포넌트입니다.
 * @returns {JSX.Element} Topics 섹션의 UI를 포함하는 JSX 요소
 */
function Topics() {
  return (
    <div>
      <h2>Topics</h2>
      Topics...
    </div>
  );
}

/**
 * Contact 섹션을 렌더링하는 함수 컴포넌트입니다.
 * @returns {JSX.Element} Contact 섹션의 UI를 포함하는 JSX 요소
 */
function Contact() {
  return (
    <div>
      <h2>Contact</h2>
      Contact...
    </div>
  );
}

/**
 * 애플리케이션의 최상위 컴포넌트입니다.
 * 모든 하위 컴포넌트(Home, Topics, Contact)를 포함하고 렌더링합니다.
 * @returns {JSX.Element} 애플리케이션 전체의 UI를 포함하는 JSX 요소
 */
function App() {
  return (
    <div>
      <h1>Hello React Router DOM</h1> {/* 제목 */}
      <Home></Home>     {/* Home 컴포넌트 렌더링 */}
      <Topics></Topics> {/* Topics 컴포넌트 렌더링 */}
      <Contact></Contact> {/* Contact 컴포넌트 렌더링 */}
    </div>
  );
}

// ID가 'root'인 DOM 요소를 찾아 React 애플리케이션을 마운트합니다.
// createRoot를 사용하여 React 18의 동시성 모드 기능을 활용할 수 있습니다.
createRoot(document.getElementById('root')).render(
  // StrictMode는 개발 모드에서만 활성화되며, 애플리케이션 내의 잠재적인 문제점(예: 오래된 라이프사이클 메서드 사용)을 경고합니다.
  <StrictMode>
    <App /> {/* App 컴포넌트를 StrictMode로 감싸 렌더링합니다. */}
  </StrictMode>
);


React router dom install

https://lshjju.tistory.com/135

 

React.js Router DOM - 리액트 라우터 돔

React Router DOM의 주요 기능 React는 '단일 페이지 애플리케이션(SPA)'을 만드는 데 주로 사용됩니다. SPA는 기본적으로 HTML 파일 하나만을 로드한 뒤, JavaScript를 통해 화면의 내용을 동적으로 바꾸는

lshjju.tistory.com

포스팅 하단 인스톨 코드 참고 하세요.



3페이지 만들고 링크로 연결 합니다.

 


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

 

위 아이들을 임포트 합니다.

// React Router DOM에서 제공하는 라우팅 관련 컴포넌트들을 import 합니다.
// BrowserRouter: HTML5 History API를 사용하여 UI를 URL과 동기화합니다.
// Route: 특정 URL 경로에 매핑될 컴포넌트를 정의합니다.
// Routes: 여러 Route 컴포넌트를 감싸고, 현재 URL과 일치하는 첫 번째 Route를 렌더링합니다.
import { BrowserRouter, Route, Routes } from "react-router-dom";

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </StrictMode>
);

 

최상위 컴포넌트인 앱컴포넌트를 브라우저라우터로 래핑합니다.

이제부터 앱은 브라우저라우터를 사용할 수 있습니다.

// ID가 'root'인 DOM 요소를 찾아 React 애플리케이션을 마운트합니다.
// createRoot를 사용하여 React 18의 권장 렌더링 방식을 따릅니다.
createRoot(document.getElementById('root')).render(
  // StrictMode로 애플리케이션을 감싸 개발 중 잠재적인 문제점을 감지하고 경고합니다.
  <StrictMode>
    {/* BrowserRouter로 전체 애플리케이션을 감싸 React Router의 라우팅 기능을 활성화합니다.
        <App /> 컴포넌트 및 그 자식 컴포넌트들에서 라우팅 관련 기능을 사용할 수 있게 됩니다. */}
    <BrowserRouter>
      <App /> {/* App 컴포넌트를 렌더링합니다. */}
    </BrowserRouter>
  </StrictMode>
);

function App() {
  return (
    <div>
      <h1>Hello React Router DOM</h1>
      <ul>
        <li>
          <a href="/">Home</a>
        </li>
        <li>
          <a href="/topics">Topics</a>
        </li>
        <li>
          <a href="/contact">Contact</a>
        </li>
      </ul>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/topics" element={<Topics />} />
        <Route path="/contact" element={<Contact />} />
        <Route path="/*" element={"Not Found"} />
      </Routes>
    </div>
  );
}

 

링크 유아이를 작성합니다.

라우트를 추가 합니다.

패스를 세팅 합니다.

예외 처리 합니다.

/**
 * 애플리케이션의 메인 컴포넌트입니다.
 * 내비게이션 링크와 React Router를 이용한 라우팅 설정을 포함합니다.
 * @returns {JSX.Element} 애플리케이션의 전체 UI를 나타내는 JSX 요소
 */
function App() {
  return (
    <div>
      <h1>Hello React Router DOM</h1> {/* 애플리케이션의 제목 */}
      <ul>
        {/* 각 페이지로 이동하는 내비게이션 링크들입니다.
            현재는 <a> 태그를 사용하여 페이지를 새로 고치지만,
            React Router의 <Link> 컴포넌트를 사용하면 SPA(Single Page Application) 방식의 라우팅이 가능합니다. */}
        <li>
          <a href="/">Home</a>
        </li>
        <li>
          <a href="/topics">Topics</a>
        </li>
        <li>
          <a href="/contact">Contact</a>
        </li>
      </ul>
      {/* Routes 컴포넌트는 자식 Route들 중에서 현재 URL과 일치하는 첫 번째 Route를 찾아 렌더링합니다. */}
      <Routes>
        {/* 경로가 '/'일 때 Home 컴포넌트를 렌더링합니다. */}
        <Route path="/" element={<Home />} />
        {/* 경로가 '/topics'일 때 Topics 컴포넌트를 렌더링합니다. */}
        <Route path="/topics" element={<Topics />} />
        {/* 경로가 '/contact'일 때 Contact 컴포넌트를 렌더링합니다. */}
        <Route path="/contact" element={<Contact />} />
        {/* 정의된 어떤 경로와도 일치하지 않을 때 ('/*' 와일드카드) "Not Found" 텍스트를 렌더링합니다.
            이는 404 페이지와 같은 역할을 합니다. */}
        <Route path="/*" element={'Not Found'} />
      </Routes>
    </div>
  );
}

test

링크 탭해서 페이지 체크 합니다.

 

이렇게 유알엘 뒤에 링크 직접 붙여서 페이지 체크 합니다.

webcontainer.io/

webcontainer.io/topics

webcontainer.io/contact

 

요상한 유알엘로 접근하면 어떻게 되는지 체크 합니다.

webcontainer.io/wtf


Completion

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import { BrowserRouter, Route, Routes } from 'react-router-dom';

function Home() {
  return (
    <div>
      <h2>Home</h2>
      Home...
    </div>
  );
}

function Topics() {
  return (
    <div>
      <h2>Topics</h2>
      Topics...
    </div>
  );
}

function Contact() {
  return (
    <div>
      <h2>Contact</h2>
      Contact...
    </div>
  );
}

function App() {
  return (
    <div>
      <h1>Hello React Router DOM</h1>
      <ul>
        <li>
          <a href="/">Home</a>
        </li>
        <li>
          <a href="/topics">Topics</a>
        </li>
        <li>
          <a href="/contact">Contact</a>
        </li>
      </ul>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/topics" element={<Topics />} />
        <Route path="/contact" element={<Contact />} />
        <Route path="/*" element={'Not Found'} />
      </Routes>
    </div>
  );
}

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </StrictMode>
);


페이지를 리로드하지 않고 데이터를 변경 합니다.


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

 

링크를 탭하면 페이지를 리로드하고 있습니다.
거시기 합니다.

리액트를 이럴라고 쓰는게 아닌데요.

개선 합니다.

Link 임포트 합니다.


      <ul>
        <li><Link to="/">Home</Link></li>
        <li><Link to="/topics">Topics</Link></li>
        <li><Link to="/contact">Contact</Link></li>
      </ul>

 

에이태그를 링크타입으로 교체합니다.

링크 탭 해 봅니다.

이제부터는 페이지가 리로드 되지 않습니다.



Hash URL 적용 합니다.


https://lshjju.tistory.com/278

 

Hash URL

해시(Hash) URL, 즉 URL의 # 뒤에 붙는 부분은 '프래그먼트 식별자(Fragment Identifier)'라고도 불립니다. 과거 싱글 페이지 애플리케이션(SPA)에서 주로 사용되었으며, 현재는 HTML5 History API의 등장으로 그

lshjju.tistory.com


import { HashRouter, Route, Routes, Link } from "react-router-dom";

 

HashRouter 임포트 합니다.


  <StrictMode>
    <HashRouter>
      <App />
    </HashRouter>
  </StrictMode>

 

브라우저라우터를 해시라우터로 교체합니다.

 

유알엘 인풋을 

webcontainer.io/

이렇게 만듭니다.

스택블리츠의 경우 링크에 마우스인 하고 하단 팝업으로 체크 합니다.

유알엘에 #이 추가됩니다.


  <StrictMode> {/* 개발 중에 잠재적인 문제를 식별하는 데 도움이 되는 추가 검사를 수행합니다. */}
    <HashRouter> {/* 웹 브라우저의 URL 해시 부분을 기반으로 라우팅을 처리하는 라우터입니다. */}
      <App /> {/* 애플리케이션의 핵심 내용을 담고 있는 App 컴포넌트를 렌더링합니다. */}
    </HashRouter>
  </StrictMode>


액티브 클래스 유아이 만들기


import { HashRouter, Route, Routes, NavLink } from "react-router-dom";

 

NavLink 임포트 합니다.


      <ul>
        <li><NavLink to="/">Home</NavLink></li>
        <li><NavLink to="/topics">Topics</NavLink></li>
        <li><NavLink to="/contact">Contact</NavLink></li>
      </ul>

 

링크를 네브링크로 교체 합니다.

 

스택블리츠에서 프리뷰를 새창으로 오픈 합니다.

 

f12 엘레멘츠 체크

탭하면 해당 에이 태그에 액티브 클래스가 생성되는지 체크 합니다.


.active {
  background-color: tomato;
  text-decoration: none;
}

 

index.css

 

원래 코드 다 삭제하고 액티브 클래스 추가합니다.

 

링크를 탭하고 액티브 유아이를 체크 합니다.

이제부터 유저가 지금 어디에 있는지를 직관적인 유아이로 표시할 수 있습니다.


test


Completion

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import { HashRouter, Route, Routes, NavLink } from 'react-router-dom';

function Home() {
  return (
    <div>
      <h2>Home</h2>
      Home...
    </div>
  );
}

function Topics() {
  return (
    <div>
      <h2>Topics</h2>
      Topics...
    </div>
  );
}

function Contact() {
  return (
    <div>
      <h2>Contact</h2>
      Contact...
    </div>
  );
}

function App() {
  return (
    <div>
      <h1>Hello React Router DOM</h1>
      <ul>
        <li>
          <NavLink to="/">Home</NavLink>
        </li>
        <li>
          <NavLink to="/topics">Topics</NavLink>
        </li>
        <li>
          <NavLink to="/contact">Contact</NavLink>
        </li>
      </ul>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/topics" element={<Topics />} />
        <Route path="/contact" element={<Contact />} />
        <Route path="/*" element={'Not Found'} />
      </Routes>
    </div>
  );
}

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <HashRouter>
      <App />
    </HashRouter>
  </StrictMode>
);


페이지에 서브 페이지와 링크를 추가 합니다.


        <Route path="/topics/*" element={<Topics />} />

 

토픽스 패스에  /*  추가합니다.


function Topics() {
  return (
    <div>
      <h2>Topics</h2>
      <ul>
        <li>
          <NavLink to="/topics/1">HTML</NavLink>
        </li>
        <li>
          <NavLink to="/topics/2">JS</NavLink>
        </li>
        <li>
          <NavLink to="/topics/3">React</NavLink>
        </li>
      </ul>
      <Routes>
        <Route path="/1" element={"HTML is ..."} />
        <Route path="/2" element={"JS is ..."} />
        <Route path="/3" element={"React is ..."} />
      </Routes>
    </div>
  );
}

 

링크 몇개 만듭니다.

라우트 설치하고 내부 데이터 추가 합니다.

// 토픽스 페이지를 나타내는 컴포넌트입니다.
// 이 컴포넌트 자체 내에 또 다른 중첩 라우팅을 포함하고 있습니다.
function Topics() {
  return (
    <div>
      <h2>Topics</h2> {/* 토픽스 페이지의 제목입니다. */}
      <ul> {/* 토픽 목록을 위한 비순서 목록입니다. */}
        <li>
          <NavLink to="/topics/1">HTML</NavLink> 
          {/* HTML 토픽으로 이동하는 NavLink입니다. */}
        </li>
        <li>
          <NavLink to="/topics/2">JS</NavLink> 
          {/* JS 토픽으로 이동하는 NavLink입니다. */}
        </li>
        <li>
          <NavLink to="/topics/3">React</NavLink> 
          {/* React 토픽으로 이동하는 NavLink입니다. */}
        </li>
      </ul>
      {/* 
        이 Routes는 /topics/* 경로 아래에서 동작하는 중첩 라우팅입니다.
        예를 들어, URL이 "/topics/1"일 경우, 이 Routes 내부에서는 path="/1"이 매칭됩니다.
      */}
      <Routes>
        <Route path="/1" element={"HTML is ..."} /> 
        {/* 경로가 "/topics/1"일 때 "HTML is ..."를 표시합니다. */}
        <Route path="/2" element={"JS is ..."} /> 
        {/* 경로가 "/topics/2"일 때 "JS is ..."를 표시합니다. */}
        <Route path="/3" element={"React is ..."} /> 
        {/* 경로가 "/topics/3"일 때 "React is ..."를 표시합니다. */}
      </Routes>
    </div>
  );
}

test

잘 작동하는지 체크합니다.


Completion

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import { HashRouter, Route, Routes, NavLink } from "react-router-dom";

function Home() {
  return (
    <div>
      <h2>Home</h2>
      Home...
    </div>
  );
}

function Topics() {
  return (
    <div>
      <h2>Topics</h2>
      <ul>
        <li>
          <NavLink to="/topics/1">HTML</NavLink>
        </li>
        <li>
          <NavLink to="/topics/2">JS</NavLink>
        </li>
        <li>
          <NavLink to="/topics/3">React</NavLink>
        </li>
      </ul>
      <Routes>
        <Route path="/1" element={"HTML is ..."} />
        <Route path="/2" element={"JS is ..."} />
        <Route path="/3" element={"React is ..."} />
      </Routes>
    </div>
  );
}

function Contact() {
  return (
    <div>
      <h2>Contact</h2>
      Contact...
    </div>
  );
}

function App() {
  return (
    <div>
      <h1>Hello React Router DOM</h1>
      <ul>
        <li>
          <NavLink to="/">Home</NavLink>
        </li>
        <li>
          <NavLink to="/topics">Topics</NavLink>
        </li>
        <li>
          <NavLink to="/contact">Contact</NavLink>
        </li>
      </ul>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/topics/*" element={<Topics />} />
        <Route path="/contact" element={<Contact />} />
        <Route path="/*" element={"Not Found"} />
      </Routes>
    </div>
  );
}

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
  <StrictMode>
    <HashRouter>
      <App />
    </HashRouter>
  </StrictMode>
);


유아이를 반복문으로 개선 합니다.

페이지 콘텐츠를 데이터 바인딩 합니다.


var contents = [
  { id: 1, title: "HTML", description: "HTML is ..." },
  { id: 2, title: "JS", description: "JS is ..." },
  { id: 3, title: "React", description: "React is ..." },
];

 

현재 네비 엘아이를 반복문으로 만든다면 유지보수가 훨씬 효율적일 것입니다.

개선 합니다.

 

펑션홈 아래에 어레이 하나 초기화 합니다.

// 토픽 데이터 배열입니다. 각 객체는 ID, 제목, 설명을 포함합니다.
// 이 배열은 애플리케이션 전체에서 공유되는 데이터 소스로 사용됩니다.
var contents = [
  { id: 1, title: "HTML", description: "HTML is ..." },
  { id: 2, title: "JS", description: "JS is ..." },
  { id: 3, title: "React", description: "React is ..." },
];

      <ul>
        {contents.map(item => (
          <li key={item.id}> 
            <NavLink to={"/topics/" + item.id}>{item.title}</NavLink> 
          </li>
        ))}
      </ul>

 

Topics

반복문으로 토픽 링크를 빌딩 합니다.

      <ul> {/* 토픽 목록을 위한 비순서 목록입니다. */}
        {/* map()은 배열의 각 항목을 변환하여 새로운 배열을 반환하며, 
        React는 이 배열의 JSX 요소들을 효율적으로 렌더링합니다. */}
        {/* 각 리스트 항목에는 고유한 'key' prop을 넣어주는 것이 중요합니다. 
        (여기서는 item.id를 사용) */}
        {contents.map(item => (
          <li key={item.id}> 
          {/* key prop은 React가 리스트를 효율적으로 업데이트하는 데 사용됩니다. */}
            <NavLink to={"/topics/" + item.id}>{item.title}</NavLink> 
            {/* 각 토픽 상세 페이지로 이동하는 링크입니다. */}
          </li>
        ))}
      </ul>

https://lshjju.tistory.com/173

 

React에서 map 함수 사용하기

React에서 map 함수 사용하기React에서 반복되는 요소들을 렌더링할 때는 주로 JavaScript의 map() 함수를 사용합니다. 이 함수는 배열의 각 요소를 순회하면서 새로운 배열을 만들어주는데, React에서는

lshjju.tistory.com


function Topic() {
  return (
    <div>
      <h3>Topic</h3>
      Topic...
    </div>
  );
}

 

펑션 토픽스 위에 펑션 토픽을 추가 합니다.


      <Routes>
        <Route path="/:topic_id" element={<Topic />} />
      </Routes>

 

Topics

유저가 탭한 링크가 패스로 세팅되어야 합니다.

그러기 위해 펑션토픽스 라우트를 업그레이드 합니다.

유저가 탭한 유알엘이 브라우저 유알엘영역에 있습니다.

즉 브라우저 유알엘 영역이 현재의 유알엘을 알고 있습니다. 

/: 는 브라우저 유알엘영역 아이디가 무엇인지 알려달라는 코드입니다.

그런데 이 기능을 사용하려면 유즈파람스가 필요 합니다.

유즈파람스 임포트 하러 갑니다.

      <Routes>
        {/*
          이 Routes는 '/topics/*' 경로 아래에서 동작하는 중첩 라우팅입니다.
          URL이 "/topics/1"일 경우, 이 Routes 내부에서는 path="/:topic_id"가 매칭되며,
          ':topic_id' 부분은 Topic 컴포넌트로 전달되어 사용됩니다.
        */}
        <Route path="/:topic_id" element={<Topic />} /> 
        {/* URL의 동적 파라미터에 따라 Topic 컴포넌트를 렌더링합니다. */}
      </Routes>

import { HashRouter, Route, Routes, NavLink, useParams } from "react-router-dom";

 

토픽아이디 밸류를 가져오기 위해 useParams를 임포트합니다.


  var params = useParams();

 

Topic

유즈파람스 기능을 사용하기 위해 리턴 위에 파람스를 초기화 합니다.

  // useParams 훅을 사용하여 URL에서 동적인 파라미터(예: /topics/123의 123)를 추출합니다.
  var params = useParams();

console.log("params", params, params.topic_id);

 

Topic

파람스 변수 아래에 로그 찍어 봅니다.

토픽스 React링크 찍고 콘솔에서 아이디3 체크합니다.

topic_id 는 라우트 패스에서 유즈파람스에게 요청한 네임입니다.

 

  // 디버깅 목적으로 params 객체와 topic_id 값을 콘솔에 출력합니다.
  console.log('params', params, params.topic_id);


  var topic_id = params.topic_id; 

  const found_topic = contents.find(item => item.id === Number(topic_id));

  const selected_topic = found_topic || {
    title: "Sorry",
    description: "Not Found",
  };

 

Topic

파람스 배리어블 아래에 파람토픽아이디 초기화 합니다.

즉 유즈파람스로 얻은 아이디를 사용합니다.

find() 메서드를 사용해서 `topic_id`에 해당하는 항목을 찾습니다.

 

A = B || C

B가 트루라면 A에 세팅하세요.

아니라면 C를 A에 세팅하세요.

여기서는 found_ topic에 데이터가 있다면 트루입니다.

데이터가 없다면 스트링데이터로 예외 처리 합니다.

  // 추출된 파라미터 객체에서 'topic_id' 값을 가져옵니다.
  var topic_id = params.topic_id;

  // contents 배열에서 URL 파라미터로 받은 topic_id와 일치하는 토픽을 찾습니다.
  // URL 파라미터는 문자열이므로 Number()를 사용하여 숫자로 변환합니다.
  const found_topic = contents.find((item) => item.id === Number(topic_id));

  // 일치하는 토픽을 찾지 못한 경우를 대비하여 기본값(Not Found)을 설정합니다.
  const selected_topic = found_topic || {
    title: 'Sorry',
    description: 'Not Found',
  };

    <div>
      <h3>{selected_topic.title}</h3> 
      {selected_topic.description} 
    </div>

 

Topic

리턴에 셀렉티드토픽 타이틀과 디스크립션을 데이터 바인딩 합니다.

    <div>
      <h3>{selected_topic.title}</h3> {/* 선택된 토픽의 제목을 표시합니다. */}
      {selected_topic.description} {/* 선택된 토픽의 설명을 표시합니다. */}
    </div>

test

잘 작동하는지 체크 합니다.


Completion

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import {
  HashRouter,
  Route,
  Routes,
  NavLink,
  useParams,
} from 'react-router-dom';

function Home() {
  return (
    <div>
      <h2>Home</h2>
      Home...
    </div>
  );
}

var contents = [
  { id: 1, title: 'HTML', description: 'HTML is ...' },
  { id: 2, title: 'JS', description: 'JS is ...' },
  { id: 3, title: 'React', description: 'React is ...' },
];

function Topic() {
  var params = useParams();

  var topic_id = params.topic_id;

  const found_topic = contents.find((item) => item.id === Number(topic_id));

  const selected_topic = found_topic || {
    title: 'Sorry',
    description: 'Not Found',
  };

  console.log('params', params, params.topic_id);

  return (
    <div>
      <h3>{selected_topic.title}</h3>
      {selected_topic.description}
    </div>
  );
}

function Topics() {
  return (
    <div>
      <h2>Topics</h2>
      <ul>
        {contents.map((item) => (
          <li key={item.id}>
            <NavLink to={'/topics/' + item.id}>{item.title}</NavLink>
          </li>
        ))}
      </ul>
      <Routes>
        <Route path="/:topic_id" element={<Topic />} />
      </Routes>
    </div>
  );
}

function Contact() {
  return (
    <div>
      <h2>Contact</h2>
      Contact...
    </div>
  );
}

function App() {
  return (
    <div>
      <h1>Hello React Router DOM</h1>
      <ul>
        <li>
          <NavLink to="/">Home</NavLink>
        </li>
        <li>
          <NavLink to="/topics">Topics</NavLink>
        </li>
        <li>
          <NavLink to="/contact">Contact</NavLink>
        </li>
      </ul>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/topics/*" element={<Topics />} />
        <Route path="/contact" element={<Contact />} />
        <Route path="/*" element={'Not Found'} />
      </Routes>
    </div>
  );
}

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <HashRouter>
      <App />
    </HashRouter>
  </StrictMode>
);

Comment ver

// React의 엄격 모드(StrictMode)를 import 합니다. 이는 개발 단계에서 잠재적인 문제점을 식별하는 데 도움을 줍니다.
import { StrictMode } from 'react';
// React 18에서 도입된 createRoot 함수를 import 합니다. 이 함수는 React 애플리케이션을 DOM에 마운트하는 데 사용됩니다.
import { createRoot } from 'react-dom/client';
// 전역 스타일을 정의하는 CSS 파일을 import 합니다.
import './index.css';
// React Router DOM에서 제공하는 라우팅 관련 컴포넌트 및 훅을 import 합니다.
import {
  HashRouter, // Hash 기반의 라우팅을 구현합니다. URL에 # 문자를 사용하여 경로를 구분합니다.
  Route, // 특정 URL 경로에 매핑될 컴포넌트를 정의합니다.
  Routes, // 여러 Route 컴포넌트를 감싸고, 현재 URL과 일치하는 첫 번째 Route를 렌더링합니다.
  NavLink, // 현재 경로와 일치할 때 활성화된 스타일을 적용할 수 있는 <Link>의 특별한 버전입니다.
  useParams, // URL 경로의 매개변수(parameter) 값을 객체 형태로 가져오는 훅입니다.
} from 'react-router-dom';

/**
 * Home 섹션의 내용을 렌더링하는 함수 컴포넌트입니다.
 * @returns {JSX.Element} Home 섹션을 나타내는 JSX 요소
 */
function Home() {
  return (
    <div>
      <h2>Home</h2>
      Home...
    </div>
  );
}

// 토픽(Topic) 목록을 담고 있는 배열입니다. 각 토픽은 id, title, description을 가집니다.
var contents = [
  { id: 1, title: 'HTML', description: 'HTML is ...' },
  { id: 2, title: 'JS', description: 'JS is ...' },
  { id: 3, title: 'React', description: 'React is ...' },
];

/**
 * 특정 토픽의 상세 내용을 렌더링하는 함수 컴포넌트입니다.
 * URL 파라미터를 통해 토픽 ID를 받아 해당 토픽의 정보를 표시합니다.
 * @returns {JSX.Element} 특정 토픽의 상세 내용을 나타내는 JSX 요소
 */
function Topic() {
  // useParams 훅을 사용하여 URL에서 동적인 파라미터(예: /topics/123의 123)를 추출합니다.
  var params = useParams();

  // 추출된 파라미터 객체에서 'topic_id' 값을 가져옵니다.
  var topic_id = params.topic_id;

  // contents 배열에서 URL 파라미터로 받은 topic_id와 일치하는 토픽을 찾습니다.
  // URL 파라미터는 문자열이므로 Number()를 사용하여 숫자로 변환합니다.
  const found_topic = contents.find((item) => item.id === Number(topic_id));

  // 일치하는 토픽을 찾지 못한 경우를 대비하여 기본값(Not Found)을 설정합니다.
  const selected_topic = found_topic || {
    title: 'Sorry',
    description: 'Not Found',
  };

  // 디버깅 목적으로 params 객체와 topic_id 값을 콘솔에 출력합니다.
  console.log('params', params, params.topic_id);

  return (
    <div>
      <h3>{selected_topic.title}</h3> {/* 선택된 토픽의 제목을 표시합니다. */}
      {selected_topic.description} {/* 선택된 토픽의 설명을 표시합니다. */}
    </div>
  );
}

/**
 * 토픽 목록과 하위 토픽 상세 페이지를 렌더링하는 함수 컴포넌트입니다.
 * 중첩 라우팅을 사용하여 특정 토픽을 클릭했을 때 상세 내용을 보여줍니다.
 * @returns {JSX.Element} 토픽 목록과 중첩 라우팅을 포함하는 JSX 요소
 */
function Topics() {
  return (
    <div>
      <h2>Topics</h2>
      <ul>
        {/* contents 배열을 순회하며 각 토픽에 대한 링크를 생성합니다. */}
        {contents.map((item) => (
          <li key={item.id}>
            {/* NavLink 컴포넌트를 사용하여 라우팅 링크를 생성합니다.
                'to' 속성은 이동할 경로를 지정하며, 동적으로 토픽 ID를 포함합니다. */}
            <NavLink to={'/topics/' + item.id}>{item.title}</NavLink>
          </li>
        ))}
      </ul>
      {/* Topics 컴포넌트 내에서 중첩 라우팅을 설정합니다.
          '/'는 현재 경로(예: /topics)를 기준으로 하위 경로를 정의합니다.
          ':topic_id'는 URL에서 변수 값을 받아 Topic 컴포넌트로 전달합니다. */}
      <Routes>
        <Route path="/:topic_id" element={<Topic />} />
      </Routes>
    </div>
  );
}

/**
 * Contact 섹션의 내용을 렌더링하는 함수 컴포넌트입니다.
 * @returns {JSX.Element} Contact 섹션을 나타내는 JSX 요소
 */
function Contact() {
  return (
    <div>
      <h2>Contact</h2>
      Contact...
    </div>
  );
}

/**
 * 애플리케이션의 메인 컴포넌트입니다.
 * 메인 내비게이션 링크와 라우팅 설정을 포함합니다.
 * @returns {JSX.Element} 애플리케이션의 전체 UI를 나타내는 JSX 요소
 */
function App() {
  return (
    <div>
      <h1>Hello React Router DOM</h1> {/* 애플리케이션의 제목 */}
      <ul>
        {/* NavLink 컴포넌트를 사용하여 각 메인 페이지로 이동하는 링크를 생성합니다. */}
        <li>
          <NavLink to="/">Home</NavLink>
        </li>
        <li>
          <NavLink to="/topics">Topics</NavLink>
        </li>
        <li>
          <NavLink to="/contact">Contact</NavLink>
        </li>
      </ul>
      {/* Routes 컴포넌트는 자식 Route들 중에서 현재 URL과 일치하는 첫 번째 Route를 찾아 렌더링합니다. */}
      <Routes>
        {/* 경로가 '/'일 때 Home 컴포넌트를 렌더링합니다. */}
        <Route path="/" element={<Home />} />
        {/* 경로가 '/topics/*'일 때 Topics 컴포넌트를 렌더링합니다.
            '/*'는 /topics/ 뒤에 어떤 경로가 오더라도 Topics 컴포넌트가 렌더링되도록 합니다.
            이는 Topics 컴포넌트 내에서 다시 중첩 라우팅이 처리될 수 있게 합니다. */}
        <Route path="/topics/*" element={<Topics />} />
        {/* 경로가 '/contact'일 때 Contact 컴포넌트를 렌더링합니다. */}
        <Route path="/contact" element={<Contact />} />
        {/* 정의된 어떤 경로와도 일치하지 않을 때 ('/*' 와일드카드) "Not Found" 텍스트를 렌더링합니다.
            이는 404 페이지와 같은 역할을 합니다. */}
        <Route path="/*" element={'Not Found'} />
      </Routes>
    </div>
  );
}

// ID가 'root'인 DOM 요소를 찾아 React 애플리케이션을 마운트합니다.
// createRoot를 사용하여 React 18의 권장 렌더링 방식을 따릅니다.
createRoot(document.getElementById('root')).render(
  // StrictMode로 애플리케이션을 감싸 개발 중 잠재적인 문제점을 감지하고 경고합니다.
  <StrictMode>
    {/* HashRouter로 전체 애플리케이션을 감싸 React Router의 라우팅 기능을 활성화합니다.
        URL의 해시(#) 부분을 사용하여 경로를 관리하므로 서버 측 설정 없이 SPA 라우팅이 가능합니다. */}
    <HashRouter>
      <App /> {/* App 컴포넌트를 렌더링합니다. */}
    </HashRouter>
  </StrictMode>
);


출처

https://wikibook.co.kr/react-rev-ebook/

 

생활코딩! React 리액트 프로그래밍 (개정판) (ebook): 처음 프로그래밍을 시작하는 입문자의 눈높이

세상에서 리액트를 가장 쉽게 설명한 입문서! 생활코딩은 일반인에게 프로그래밍을 알려주는 것을 목적으로 하는 비영리 교육 활동입니다. 이 책은 생활코딩에서 제공하는 수업 가운데 리액트

wikibook.co.kr