
html 을 서버 측에서 한번만 받아와서 웹 애플리케이션을 실행시킨 후, 이후에는 필요한 데이터만 받아와서 화면에 업데이트하는 것
=> 리액트 같은 라이브러리를 사용하여 뷰 렌더링을 사용자의 브라우저가 담당
링크를 눌러 다른 페이지로 이동할 때 서버에 다른 페이지의 html을 새로 요청하는 것이 아닌, 브라우저의 History API를 사용하여 브라우저의 주소창의 값만 변경하고 기존에 페이지에 띄웠던 웹 앱을 그대로 유지하면서 라우팅 설정에 따라 또 다른 페이지를 보여주게 됨.
//index.js
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
💡 BrowserRouter 가 SPA를 가능케 함.
BrowserRouter로 감싸야만 Routes/Route 쓸 수 있음!<BrowserRouter>wraps<App />, which means that all components inside<App />will have access to React Router functionalities (like navigating between pages). This allows the app to use route-based navigation (<Route>,<Link>,useNavigate(), etc.) without needing full-page reloads.
- What Exactly Does
<BrowserRouter>Do?
✅ Manages the URL history (without full-page reloads).
✅ Listens for URL changes and renders the correct page/component.
✅ Provides routing context to all components inside<App />.
- How It Works:
Normally, in a traditional website, when you click a link, the browser makes a request to the server for a new page.
With React Router (<BrowserRouter>), URL changes are handled inside JavaScript without making a new server request.
This makes React apps faster since only the necessary components are updated instead of reloading the entire page.
//App.js
import { Route, Routes } from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
);
}
export default App;
//Home.js
import React from "react";
import { Link } from "react-router-dom";
const Home = () => {
return (
<div>
<h1>Home</h1>
<p>First Page</p>
<Link to="/about">About</Link>
</div>
);
};
export default Home;
//App.js
import { Route, Routes } from "react-router-dom";
(...)
<Routes>
(...)
<Route path="/profile/:username" element={<Profile />} />
</Routes>
//Home.js
import { Link } from "react-router-dom";
(...)
<div>
<ul>
<li>
<Link to="/profile/velopert">velopert</Link>
</li>
<li>
<Link to="/profile/gildong">gildong</Link>
</li>
<li>
<Link to="/profile/unknown">존재하지 않는 프로필</Link>
</li>
</ul >
</div>
);
};
import React from "react";
import { useParams } from "react-router-dom";
const data = {
velopert: {
name: "김민준",
description: "리액트를 좋아하는 개발자",
},
gildong: {
name: "홍길동",
description: "고전 소설 홍길동전의 주인공",
},
};
const Profile = () => {
const params = useParams();
const profile = data[params.username];
return (
<div>
<h1> 사용자 프로필 </h1>
{profile ? (
<div>
<h3>
{params.username} ({profile.name})
</h3>
<p>{profile.description}</p>
</div>
) : (<div>존재하지 않는 사용자입니다.</div>)}
</div>
);
};
export default Profile;
useParams, Link 를 react-router-dom 에서 import 하자!
💡 여기서 갑자기 든 의문!
data같은 독립적인 객체를ProfileComponent 안에 선언하는 것과 밖에 선언하는 것의 차이점은 뭘까? 당연히 component에서 일어나는 event handling 함수 같은 경우에는 component 안에 써야한다. 그렇다면data객체는 왜 밖에 썼을까? 만약 component 안에 썼다면Profilecomponent가 렌더링 될 때마다 새로운data객체가 생성 됐을 것이기 때문에 비효율적이다.
💡 URL parameter 와 달리 Route 컴포넌트 사용시 별도로 설정해야 하는 것이 없다.

http://localhost:3000/about?detail=true&mode=1 라는 쿼리 스트링
useSearchParams이 ?을 지우고 &로 분류한 뒤 뒤 key와 value값을 =로 파싱함.
//Before App.js
<Route path="/articles" element={<Articles />} />
<Route path="/article/:id" element={<Article />} />
//After App.js
<Route path="/articles" element={<Articles />}>
<Route path=":id" element={<Article />} />
</Route>
// Articles.js
<div>
<Outlet />
<ul>
<li>
<Link to="/articles/1">Article 1</Link>
</li>
(...)
</ul>
</div>
Outlet/>을 쓰면<Route path=":id" element={<Article />} />를 보여줌. (Route의 children 으로 들어가는 JSX element 를 보여주는 역할)


Article page 를 열었을 때 Article List가 보이는 것을 볼 수 있다!
//App.js
<Route element={<Layout />}>
<Route index element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/profile/:username" element={<Profile />} />
</Route>
import React from "react";
import { Outlet } from "react-router-dom";
const Layout = () => {
return (
<div>
<header style={{ background: "lightgray", padding: 16, fonstsize: 24 }}>
header
</header>
<main>
<Outlet />
</main>
</div>
);
};
export default Layout;
이런 식으로 Outlet를 이용하면 "home", "about", "profile" 페이지에서 Layout component 를 보여줄 수 있다.
const Layout = () => {
const navigate = useNavigate();
const goBack = () => {
navigate(-1);
};
const goArticles = () => {
navigate("/articles", { replace: true });
};
return (
<div>
<header style={{ background: "lightgray", padding: 16, fonstsize: 24 }}>
<button onClick={goBack}>뒤로가기</button>
<button onClick={goArticles}>게시글로 이동</button>
(...)
-1 은 한번 뒤로가기 2은 두번 앞으로가기
replace: true 옵션은 페이지 이동 시 현재 페이지를 페이지 기록에 남기지 않는다.
react-router-dom의Link component 대신 쓸 수 있다.
링크에서 사용하는 경로가 현재 라우트의 경로와 일치하는 경우 특정 스타일 또는 CSS 클래스를 적용하는 컴포넌트

//Before
import React from "react";
import { NavLink, Outlet } from "react-router-dom";
const Articles = () => {
const activeStyle = {
color: "green",
fontsize: "21",
};
return (
<div>
<Outlet />
<ul>
<li>
<NavLink
to="/articles/1"
style={({ isActive }) => (isActive ? activeStyle : undefined)}
>
Article 1
</NavLink>
</li>
<li>
<NavLink
to="/articles/2"
style={({ isActive }) => (isActive ? activeStyle : undefined)}
>
Article 2
</NavLink>
</li>
<li>
<NavLink
to="/articles/3"
style={({ isActive }) => (isActive ? activeStyle : undefined)}
>
Article 3
</NavLink>
</li>
</ul>
</div>
);
};
export default Articles;
//After
import React from "react";
import { NavLink, Outlet } from "react-router-dom";
const Articles = () => {
return (
<div>
<Outlet />
<ul>
<ArticleItem id={1} />
<ArticleItem id={2} />
<ArticleItem id={3} />
</ul>
</div>
);
};
const ArticleItem = ({ id }) => {
const activeStyle = {
color: "green",
fontsize: "21",
};
return (
<li>
{" "}
<NavLink
to="/articles/1"
style={({ isActive }) => (isActive ? activeStyle : undefined)}
>
Article 1
</NavLink>
</li>
);
};
export default Articles;
NavLink 의 style과 className은 {isActive: boolean}을 파라미터로 전달바는 함수 타입의 값을 전달한다.
<NavLink to="/articles/1" style={({ isActive }) => (isActive ? activeStyle : undefined)} />
<Route path="*" element={<div>404 Not Found</div>} />
이 라우트 element 상단에 위치하는 사우트들의 규칙을 모두 확인하고, 일치하는 라우트가 없다면 이 라우트가 화면에 나타난다.
따라서
path="*"는 모든 Route Component들 중 최하단에 서 불러야한다.

페이지를 리다이렉트하고 싶을 때
사용자의 로그인이 필요한 페이지인데 로그인을 안했다면 로그인 페이지로 리다이렉트 해야한다!!
//Login.js
import React from 'react';
export default const Login = () => {
return (
<div>
로그인 페이지
</div>
);
};
//MyPage.js
import React from 'react';
import { Navigate } from 'react-router-dom';
export default MyPage = () => {
const isLoggedIn = false;
if (!isLoggedIn) return <Navigate to="/login" />;
return (
<div>
마이 페이지
</div>
);
};
본 후기는 [한글과컴퓨터x한국생산성본부x스나이퍼팩토리] 한컴 AI 아카데미 (B-log) 리뷰로 작성 되었습니다.
#한컴AI아카데미 #AI개발자 #AI개발자교육 #한글과컴퓨터 #한국생산성본부 #스나이퍼팩토리 #부트캠프 #AI전문가양성 #개발자교육 #개발자취업