1. 라우터 설정 (BrowserRouter)
리액트 앱에서 라우터를 사용하려면 react-router-dom 라이브러리를 설치하고, 앱을 감싸는 BrowserRouter를 설정해야 합니다. 이를 통해 브라우저의 주소와 페이지를 동적으로 매핑할 수 있습니다.
c:\javascript\my-cra-app> npm install react-router-dom
import React from 'react'; // React 라이브러리 임포트
import ReactDOM from 'react-dom/client'; // ReactDOM 라이브러리 임포트
import './index.css'; // 스타일시트 임포트
import App from './App'; // App 컴포넌트 임포트
import reportWebVitals from './reportWebVitals'; // 웹 성능 측정 임포트
import { BrowserRouter } from 'react-router-dom'; // react-router-dom에서 BrowserRouter 임포트
const root = ReactDOM.createRoot(document.getElementById('root')); // 'root' id를 가진 DOM 요소에 React 앱을 렌더링
root.render(
// BrowserRouter로 App 컴포넌트를 감싸서 라우팅 기능을 사용할 수 있도록 함
<BrowserRouter>
<App /> {/* App 컴포넌트 렌더링 */}
</BrowserRouter>
);
2. 라우팅할 페이지 컴포넌트 생성
index.css
/* 기본 스타일 초기화 */
* {
margin: 0; /* 모든 요소의 기본 마진을 제거 */
padding: 0; /* 모든 요소의 기본 패딩을 제거 */
box-sizing: border-box; /* 모든 요소의 박스 사이즈를 border-box로 설정 (패딩과 보더가 width에 포함) */
}
body {
font-family: Arial, sans-serif; /* 기본 글꼴을 Arial로 설정 */
line-height: 1.6; /* 줄 간격을 1.6으로 설정 */
background-color: #f4f4f4; /* 배경색을 연한 회색으로 설정 */
color: #333; /* 글자 색을 어두운 회색으로 설정 */
padding: 20px; /* body에 20px 패딩을 추가 */
}
/* 헤더 스타일 */
header {
background-color: #35424a; /* 헤더 배경색을 어두운 파란색으로 설정 */
color: #ffffff; /* 텍스트 색을 흰색으로 설정 */
padding: 20px 0; /* 상하 패딩을 20px로 설정 */
text-align: center; /* 텍스트를 중앙 정렬 */
margin-bottom: 20px; /* 아래쪽에 20px 마진을 추가 */
}
header h1 {
margin: 0; /* 헤더 제목의 기본 마진을 제거 */
}
/* 네비게이션 스타일 */
nav ul {
list-style: none; /* 기본 리스트 스타일을 제거 */
padding: 0; /* 패딩 제거 */
}
nav ul li {
display: inline; /* 리스트 항목을 인라인으로 배치 */
margin: 0 10px; /* 각 항목 간에 10px 간격 추가 */
}
nav ul li a {
color: #ffffff; /* 링크 색상을 흰색으로 설정 */
text-decoration: none; /* 링크의 밑줄을 제거 */
font-weight: bold; /* 링크 텍스트를 굵게 설정 */
}
nav ul li a:hover {
text-decoration: underline; /* 마우스를 올렸을 때 밑줄을 표시 */
}
/* 메인 콘텐츠 스타일 */
main {
background-color: #ffffff; /* 배경색을 흰색으로 설정 */
padding: 20px; /* 패딩 20px 추가 */
border-radius: 8px; /* 모서리를 둥글게 처리 */
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 가벼운 그림자를 추가 */
}
main h2 {
color: #35424a; /* 제목 색상을 어두운 파란색으로 설정 */
margin-bottom: 10px; /* 제목과 본문 간격을 10px로 설정 */
}
main p {
margin-bottom: 20px; /* 본문 내용 간격을 20px로 설정 */
}
/* 푸터 스타일 */
footer {
background-color: #35424a; /* 푸터 배경색을 어두운 파란색으로 설정 */
color: #ffffff; /* 텍스트 색을 흰색으로 설정 */
text-align: center; /* 텍스트 중앙 정렬 */
padding: 10px 0; /* 상하 패딩을 10px로 설정 */
margin-top: 20px; /* 푸터와 위 콘텐츠 사이에 20px 마진 추가 */
border-radius: 8px; /* 모서리를 둥글게 처리 */
}
footer p {
margin: 0; /* 푸터 텍스트의 마진을 제거 */
}
Home.js
export default function Home() {
return (
<>
{/* 헤더 영역 */}
<header>
<h1>Welcome to Our Website!</h1>
<nav>
<ul>
{/* 내비게이션 링크 */}
<li><a href="home.html">Home</a></li>
<li><a href="about.html">About</a></li>
<li><a href="contact.html">Contact</a></li>
</ul>
</nav>
</header>
{/* 메인 콘텐츠 영역 */}
<main>
{/* 소개 섹션 */}
<section>
<h2>Introduction</h2>
<p>We are glad to have you here. Explore our website to learn more about what we offer.</p>
</section>
{/* 최신 뉴스 섹션 */}
<section>
<h2>Latest News</h2>
<p>Stay tuned for the latest updates and news from our team.</p>
</section>
</main>
{/* 푸터 영역 */}
<footer>
<p>© 2024 Our Website. All rights reserved.</p>
</footer>
</>
);
};
About.js
export default function About() {
return (
<>
{/* 헤더 영역 */}
<header>
<h1>About Us</h1>
<nav>
<ul>
{/* 내비게이션 링크 */}
<li><a href="home.html">Home</a></li>
<li><a href="about.html">About</a></li>
<li><a href="contact.html">Contact</a></li>
</ul>
</nav>
</header>
{/* 메인 콘텐츠 영역 */}
<main>
{/* 우리의 미션 섹션 */}
<section>
<h2>Our Mission</h2>
<p>Our mission is to provide exceptional services and products that improve the lives of our customers.</p>
</section>
{/* 우리 팀 섹션 */}
<section>
<h2>Our Team</h2>
<p>We are a group of passionate individuals committed to delivering the best results.</p>
</section>
{/* 우리의 역사 섹션 */}
<section>
<h2>Our History</h2>
<p>Since our founding, we have continuously grown and expanded our services, always putting our customers first.</p>
</section>
</main>
{/* 푸터 영역 */}
<footer>
<p>© 2024 Our Website. All rights reserved.</p>
</footer>
</>
)
};
3. Routes와 Route
- Routes: 여러 개의 Route 컴포넌트를 감싸는 역할을 합니다.
- Route: path와 element 속성을 통해 경로와 해당 경로에서 보여줄 컴포넌트를 매핑합니다.
App.js
import { Route, Routes } from "react-router-dom"; // React Router에서 Route와 Routes 컴포넌트를 가져옵니다.
import About from "./About"; // About 컴포넌트를 가져옵니다.
import Home from "./Home"; // Home 컴포넌트를 가져옵니다.
const App = () => {
return (
<>
{/* Routes 컴포넌트를 사용하여 여러 경로와 해당 경로에 맞는 컴포넌트를 렌더링합니다. */}
<Routes>
{/* "/" 경로로 접근하면 Home 컴포넌트를 렌더링 */}
<Route path="/" element={<Home />} />
{/* "/about" 경로로 접근하면 About 컴포넌트를 렌더링 */}
<Route path="/about" element={<About />} />
</Routes>
</>
);
};
export default App; // App 컴포넌트를 내보냅니다.
4. Link 컴포넌트
<Link>는 HTML의 <a> 태그와 비슷하지만, 페이지를 새로 고침하지 않고 주소만 변경할 수 있습니다. 이를 통해 리액트 앱 내에서 페이지 전환을 할 수 있습니다.
App.js
import { Route, Routes, Link } from "react-router-dom"; // React Router에서 Route, Routes, Link 컴포넌트를 가져옵니다.
import About from "./About"; // About 컴포넌트를 가져옵니다.
import Home from "./Home"; // Home 컴포넌트를 가져옵니다.
const App = () => {
return (
<>
{/* 페이지 내비게이션을 위한 링크. 'Link' 컴포넌트를 사용하여 경로 간 이동을 처리합니다. */}
<Link to="/">홈</Link> {/* '/' 경로로 이동하는 링크 */}
|
<Link to="/about">소개</Link> {/* '/about' 경로로 이동하는 링크 */}
{/* Routes 컴포넌트 안에 정의된 각 경로에 따라 렌더링될 컴포넌트를 설정합니다. */}
<Routes>
{/* "/" 경로로 접근하면 Home 컴포넌트를 렌더링 */}
<Route path="/" element={<Home />} />
{/* "/about" 경로로 접근하면 About 컴포넌트를 렌더링 */}
<Route path="/about" element={<About />} />
</Routes>
</>
);
};
export default App; // App 컴포넌트를 내보냅니다.
5. 가변 데이터 전달: URL 파라미터와 쿼리 문자열
- URL 파라미터 (useParams): URL 경로에 포함된 동적인 데이터를 전달할 때 사용됩니다. 예: /profile/:userid → useParams 훅으로 파라미터값을 추출합니다.
App.js
import { Route, Routes, Link } from "react-router-dom"; // React Router에서 Route, Routes, Link 컴포넌트를 가져옵니다.
import About from "./About"; // About 컴포넌트를 가져옵니다.
import Home from "./Home"; // Home 컴포넌트를 가져옵니다.
import Profile from "./Profile"; // Profile 컴포넌트를 가져옵니다.
const App = () => {
return (
<>
{/* 페이지 내비게이션을 위한 링크. 'Link' 컴포넌트를 사용하여 경로 간 이동을 처리합니다. */}
<Link to="/">홈</Link> {/* '/' 경로로 이동하는 링크, Home 컴포넌트로 이동 */}
|
<Link to="/about">소개</Link> {/* '/about' 경로로 이동하는 링크, About 컴포넌트로 이동 */}
|
<Link to="/info">정보</Link> {/* '/info' 경로로 이동하는 링크, About 컴포넌트로 이동 */}
|
{/* 각 프로파일에 대한 링크 생성 */}
<Link to="/profile/mrgo">고길동 프로파일</Link> {/* '/profile/mrgo' 경로로 이동, 고길동 프로파일을 보여줌 */}
|
<Link to="/profile/mrhong">홍길동 프로파일</Link> {/* '/profile/mrhong' 경로로 이동, 홍길동 프로파일을 보여줌 */}
|
<Link to="/profile/mrshin">신길동 프로파일</Link> {/* '/profile/mrshin' 경로로 이동, 신길동 프로파일을 보여줌 */}
{/* Routes 컴포넌트 내에 정의된 경로에 맞는 컴포넌트를 렌더링 */}
<Routes>
<Route path="/" element={<Home />} /> {/* "/" 경로로 접근하면 Home 컴포넌트를 렌더링 */}
<Route path="/about" element={<About />} /> {/* "/about" 경로로 접근하면 About 컴포넌트를 렌더링 */}
<Route path="/info" element={<About />} /> {/* "/info" 경로로 접근하면 About 컴포넌트를 렌더링 */}
<Route path="/profile/:userid" element={<Profile />} /> {/* "/profile/:userid" 경로로 접근하면 Profile 컴포넌트를 렌더링 */}
</Routes>
</>
);
};
export default App; // App 컴포넌트를 내보냅니다.
Profile.js
import { useParams } from "react-router-dom"; // react-router-dom에서 useParams 훅을 가져옵니다. 이 훅은 URL의 파라미터를 가져오는 데 사용됩니다.
const userDatas = { // 사용자 정보 객체. 각 사용자의 프로필 데이터가 포함되어 있습니다.
mrgo: {
name: "고길동", // 고길동의 이름
desc: "둘리를 싫어하는 자", // 고길동의 설명
},
mrhong: {
name: "홍길동", // 홍길동의 이름
desc: "호부호형을 원하는 자", // 홍길동의 설명
},
};
const Profile = () => {
const param = useParams(); // URL에서 파라미터를 가져옵니다. 이 경우 :userid를 가져옵니다.
console.log(param); // 파라미터를 콘솔에 출력하여 확인합니다.
// userDatas 객체에서 URL 파라미터에 해당하는 사용자 정보를 가져옵니다.
const userData = userDatas[param.userid];
return (
<>
{
userData ? ( // 만약 사용자 데이터가 존재하면
<div>
<p>이름: {userData.name}</p> {/* 사용자 이름 표시 */}
<p>설명: {userData.desc}</p> {/* 사용자 설명 표시 */}
</div>
) : ( // 사용자 데이터가 없다면
<div>일치하는 사용자가 없습니다.</div> {/* 일치하는 사용자가 없다는 메시지 표시 */}
)
}
</>
);
};
export default Profile; // Profile 컴포넌트를 내보냅니다.
- 쿼리 문자열 (useLocation, useSearchParams): URL의 ?key=value 형태로 전달되는 데이터를 처리할 수 있습니다. 예: /about?detail=true → useLocation 또는 useSearchParams 훅을 사용하여 쿼리 문자열을 추출하고 조건부 렌더링을 할 수 있습니다.
c:\javascript\my-cra-app> npm install qs
About.js - useLocation
import { useLocation } from "react-router-dom"; // react-router-dom에서 useLocation 훅을 가져옵니다.
import qs from 'qs'; // qs는 쿼리 문자열을 파싱하는 라이브러리입니다.
export default function About() {
// useLocation 훅을 사용하여 현재 URL의 위치 정보 (location 객체)를 가져옵니다.
const location = useLocation(); // 현재 URL에 대한 정보가 담긴 객체
console.log(location); // 콘솔에 location 객체 출력 (디버깅용)
// location.search는 URL에서 '?' 이후의 쿼리 문자열을 포함합니다.
// qs.parse()는 이를 파싱하여 객체로 변환해줍니다. { ignoreQueryPrefix: true }는 '?'를 무시하도록 합니다.
const query = qs.parse(location.search, { ignoreQueryPrefix: true });
console.log(query); // 파싱된 쿼리 객체를 콘솔에 출력 (디버깅용)
return (
<>
<header>
<h1>About Us</h1>
<nav>
<ul>
{/* 각 페이지로 이동할 수 있는 링크들 */}
<li><a href="home.html">Home</a></li>
<li><a href="about.html">About</a></li>
<li><a href="contact.html">Contact</a></li>
</ul>
</nav>
</header>
<main>
{/* query.detail === 'true'가 참일 경우 상세 내용 출력 */}
{
query.detail === 'true' && <h2>상세 내용입니다.</h2>
}
{/* 페이지의 기본 내용 */}
<section>
<h2>Our Mission</h2>
<p>Our mission is to provide exceptional services and products that improve the lives of our customers.</p>
</section>
<section>
<h2>Our Team</h2>
<p>We are a group of passionate individuals committed to delivering the best results.</p>
</section>
<section>
<h2>Our History</h2>
<p>Since our founding, we have continuously grown and expanded our services, always putting our customers first.</p>
</section>
</main>
<footer>
<p>© 2024 Our Website. All rights reserved.</p>
</footer>
</>
)
};
About.js - useSearchParams
import { useSearchParams } from "react-router-dom"; // useSearchParams 훅을 가져옵니다.
export default function About() {
// useSearchParams 훅을 사용하여 쿼리 파라미터를 가져옵니다.
const [searchParam, setSearchParam] = useSearchParams(); // searchParam은 현재 쿼리 파라미터를 반환합니다.
// URL에서 'detail' 파라미터의 값을 가져옵니다.
const detail = searchParam.get('detail'); // detail 파라미터가 있으면 그 값을 반환합니다.
console.log(detail); // 콘솔에 detail 값을 출력하여 확인합니다.
return (
<>
<header>
<h1>About Us</h1>
<nav>
<ul>
<li><a href="home.html">Home</a></li> {/* Home 링크 */}
<li><a href="about.html">About</a></li> {/* About 링크 */}
<li><a href="contact.html">Contact</a></li> {/* Contact 링크 */}
</ul>
</nav>
</header>
<main>
{/* detail 파라미터가 'true'일 경우 상세 내용을 표시 */}
{detail === 'true' && <h2>상세 내용입니다.</h2>}
{/* About 페이지의 기본 내용 */}
<section>
<h2>Our Mission</h2>
<p>Our mission is to provide exceptional services and products that improve the lives of our customers.</p>
</section>
<section>
<h2>Our Team</h2>
<p>We are a group of passionate individuals committed to delivering the best results.</p>
</section>
<section>
<h2>Our History</h2>
<p>Since our founding, we have continuously grown and expanded our services, always putting our customers first.</p>
</section>
</main>
<footer>
<p>© 2024 Our Website. All rights reserved.</p>
</footer>
</>
)
};
6. 서브 라우트 (중첩 라우트)
Route 컴포넌트를 중첩하여, 하나의 경로에서 다른 라우트를 포함할 수 있습니다. 예를 들어, Profile 페이지 내에서 다른 경로를 중첩시킬 수 있습니다.
Profiles.js
import { Link, Outlet } from 'react-router-dom'; // Link와 Outlet 컴포넌트를 react-router-dom에서 가져옵니다.
export default function Profiles() {
return (
<>
<h3>사용자 목록</h3>
{/* 사용자 프로파일로 이동하는 링크들 */}
<Link to="/profiles/mrgo">고길동 프로파일</Link>
| <Link to="/profiles/mrhong">홍길동 프로파일</Link>
| <Link to="/profiles/mrshin">신길동 프로파일</Link>
{/* 서브 라우트가 렌더링될 위치 */}
<Outlet />
</>
);
}
App.js
import { Route, Routes, Link } from "react-router-dom"; // React Router에서 필요한 컴포넌트들을 가져옵니다.
import About from "./About"; // About 컴포넌트
import Home from "./Home"; // Home 컴포넌트
import Profile from "./Profile"; // Profile 컴포넌트
import Profiles from "./Profiles"; // Profiles 컴포넌트
const App = () => {
return (
<>
{/* 네비게이션 링크 */}
<Link to="/">홈</Link> | <Link to="/about">소개</Link> | <Link to="/info">정보</Link>
{/* 프로파일 목록으로 이동하는 링크 */}
| <Link to="/profiles">프로파일</Link>
{/* Routes 설정 */}
<Routes>
<Route path="/" element={<Home />} /> {/* 홈 경로 설정 */}
<Route path="/about" element={<About />} /> {/* 소개 경로 설정 */}
<Route path="/info" element={<About />} /> {/* 정보 경로 설정 */}
<Route path="/profiles" element={<Profiles />}> {/* 프로파일 목록 페이지 */}
<Route path=":userid" element={<Profile />} /> {/* 특정 사용자의 프로파일을 보여주는 서브 라우트 */}
</Route>
</Routes>
</>
);
};
export default App;
7. 공통 레이아웃 컴포넌트
중첩 라우트와 Outlet 컴포넌트를 이용해 각 페이지에서 공통적으로 보여줘야 하는 레이아웃을 처리할 때 유용합니다.
Layout.js
import { Link, Outlet } from "react-router-dom"; // react-router-dom에서 Link와 Outlet을 가져옵니다.
export default function Layout() {
return (
<>
{/* 헤더 영역: 네비게이션 메뉴 */}
<header style={{ background: 'lightgray', padding: 16, fontSize: 24 }}>
{/* 각 메뉴를 Link로 생성. 클릭 시 해당 경로로 이동 */}
<Link to="/">홈</Link> |
<Link to="/about">소개</Link> |
<Link to="/info">정보</Link> |
<Link to="/profiles">프로파일</Link>
</header>
<main>
{/* 서브 라우트가 렌더링될 위치 */}
<Outlet /> {/* Outlet은 하위 경로에서 컴포넌트를 렌더링합니다. */}
</main>
</>
);
}
App.js
import { Route, Routes } from "react-router-dom"; // react-router-dom에서 Route와 Routes를 가져옵니다.
import About from "./About"; // About 컴포넌트
import Home from "./Home"; // Home 컴포넌트
import Profile from "./Profile"; // Profile 컴포넌트
import Profiles from "./Profiles"; // Profiles 컴포넌트
import Layout from "./Layout"; // Layout 컴포넌트 (메뉴와 Outlet 포함)
const App = () => {
return (
<>
{/* Routes: URL 경로에 맞는 컴포넌트를 렌더링 */}
<Routes>
{/* Layout 컴포넌트로 전체 페이지 감싸기 */}
<Route element={<Layout />}>
{/* 기본 홈 경로 */}
<Route path="/" element={<Home />} />
{/* 소개 페이지 경로 */}
<Route path="/about" element={<About />} />
{/* 정보 페이지 경로 */}
<Route path="/info" element={<About />} />
{/* 프로파일 목록 페이지 경로 */}
<Route path="/profiles" element={<Profiles />}>
{/* 프로파일 서브 라우트 경로 (사용자별 프로파일 페이지) */}
<Route path=":userid" element={<Profile />} />
</Route>
</Route>
</Routes>
</>
);
};
export default App;
*생성형 AI 활용한 클라우드&보안 전문가 양성캠프 과정의 교육내용 정리 자료입니다.
'코딩 > 리액트' 카테고리의 다른 글
[새싹 성동 2기] React Router 부가 기능(네비게이션, 스타일링, 리다이렉션) (0) | 2024.12.06 |
---|---|
[새싹 성동 2기] Context API와 useContext 훅을 사용하여 테마 적용하기 (1) | 2024.12.06 |
[새싹 성동 2기] useMemo, useCallback, React.memo 활용법 (1) | 2024.12.06 |
[새싹 성동 2기] useReducer를 활용한 상태 관리 (0) | 2024.12.06 |
[새싹 성동 2기] 리액트 앱에서 국가와 국기 정보를 출력하는 방법 (1) | 2024.11.19 |