라우터란?
- 화면에 보여질 컴포넌트를 동적으로 전환할 수 있도록 하는 기능입니다.
- 구체적으로 설명하자면, 화면에 보여질 컴포넌트들을 사용자가 URL에 맞추어 구성하는 것입니다.
- 리액트의 컴포넌트만으로도 화면을 구성할 수 는 있지만, 다양한 사용자의 요청에 대해서 동적으로 화면을 구성하고 동적으로 바꾸려면 라우팅 기능은 필수입니다.
index.js와 라우터
App.js 파일도 거슬러 올라가면 Router로 구성되어 있습니다. BrowserRouter라는 태그로 감싸진 형태입니다.
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: <https://bit.ly/CRA-vitals>
reportWebVitals();
리액트의 라우터를 사용하려면 리액트 라우터를 설치해야합니다.
npm install react-router-dom
위의 명령어를 입력하여 라우터를 설치합니다.
라우터 사용하기
- 라우터를 설치했다면 라우터를 컴포넌트에서 사용하면 됩니다.
- 아래의 소스코드처럼 라우터를 import해서 라우터 태그에 컴포넌트 태그를 assign 합니다.
import "./App.css";
import "./asset/Custom.css";
import "./asset/Router.css";
import { useState } from "react";
import { Route, Route, Link} from "react-router-dom";
// 컴포넌트 삽입
import HomeComp from "./components/HomeComp";
import AboutComp from "./components/AboutComp";
const App = () => {
const [name] = useState("Router");
return (
<>
<div className="main-header">
<p>
React의 <span>{name}</span> 에 대해 알아보기
</p>
</div>
<div className="header-menu">
<Link to="/">홈</Link>
<Link to="/about">소개</Link>
</div>
<Routes>
<Route path="/" element={<HomeComp />} />
<Route path="/about" element={<AboutComp />} />
</Routes>
</>
);
};
export default App;

라우터와 Link 태그
- 리액트의 라우터는 Link라고 하는 태그를 지원합니다.
- Link 태그는 Route 태그를 통해 생성한 엘리먼트가 Routes 태그에 비로소 보이도록 제어합니다.
- Link 태그는 Link 태그의 to 경로와 Route 태그의 path 경로가 같은 컴포넌트를 보여줍니다.
<Link to="/">홈</Link>
<Link to="/about">소개</Link>
라우터의 url 파라미터
- Route 태그의 path 속성이나 Link 태그의 to 속성은 주소를 가질 수 있습니다.
- 이 주소 속에는 사용자가 요청한 정보가 담길 수 있습니다. (페이지 정보, 카테고리 분류 등)
- 리액트에서는 이러한 주소에서 정보를 가져와 핸들링 할 수 있습니다.
import { useParams } from "react-router-dom";
const data = {
jo: {
name: "jwh",
desc: "1-hee",
},
lee: {
name: "lee",
desc: "lee lee lee",
},
};
const ProfileComp01 = () => {
const params = useParams();
const profile = data[params.username];
return (
<>
<div className="comp func-comp route-comp">
<h1>사용자 프로필</h1>
{profile ? (
<div>
<h2> {profile.name}</h2>
<p> {profile.desc}</p>
</div>
) : (
<p>존재하지 않는 프로필입니다.</p>
)}
</div>
</>
);
};
export default ProfileComp01;
→ ProfileComp01.js
import "./App.css";
import "./asset/Custom.css";
import "./asset/Router.css";
import { useState } from "react";
import { Route, Routes, Link } from "react-router-dom";
// 컴포넌트 삽입
import HomeComp from "./components/HomeComp";
import AboutComp from "./components/AboutComp";
import ProfileComp01 from "./components/ProfileComp01";
const App = () => {
const [name] = useState("Router");
const names = ["jo", "lee", "hey"];
const linkList = names.map((name) => (
<Link to={`/profiles/${name}`} element={ProfileComp01}>
{name}
</Link>
));
return (
<>
<div className="main-header">
<p>
React의 <span>{name}</span> 에 대해 알아보기
</p>
</div>
<div className="header-menu">
<Link to="/">홈</Link>
<Link to="/about">소개</Link>
{linkList}
</div>
<Routes>
{/* <Route path="/" element={<HomeComp />} /> */}
{/* <Route index element={<HomeComp />} />{" "}
<Route path="/about" element={<AboutComp />} /> */}
{/* URL 파라미터로 링크 형성 */}
<Route path="/" element={<HomeComp />} />
<Route path="/about" element={<AboutComp />} />
<Route path="/profiles/:username" element={<ProfileComp01 />} />
</Routes>
</>
);
};
export default App;
→ App.js
라우터의 쿼리스트링
- 사용자가 요청하는 경로 중에 ?path=123&color='yellow' 와 같이 사용자가 요청한 경로 중에서 key-value 쌍으로 이루어진 경로의 일부분을 쿼리스트링이라고 합니다.
- 쿼리스트링은 http 통신의 get 방식에서 데이터를 송수신하는데 자주 활용됩니다.
- 리액트의 라우터에서 쿼리스트링의 데이터를 핸들링 하려면 useLocation 이 필요합니다.
- Hook의 일종이며, useLocation() 함수를 통해 location 객체를 얻어내어 프로퍼티로 여러 정보에 접근할 수 있습니다.
import { useLocation } from "react-router-dom";
const ProfileComp02 = () => {
const location = useLocation();
return (
<>
<div className="comp func-comp route-comp">
<h1>쿼리스트링 예제</h1>
<p>location 객체 정보</p>
<p>path-name : {location.pathname}</p>
<p>search : {location.search}</p>
<p>hash : {location.hash}</p>
<p>state : {location.state}</p>
<p>key : {location.key}</p>
</div>
</>
);
};
export default ProfileComp02;
- 쿼리스트링의 정보는 location 객체로부터 얻어낼 수 있습니다.

useLocation()의 프로퍼티
- pathname : 현재 주소의 경로(쿼리스트링을 제외)
- search: 쿼리스트링의 시작임을 의미하는 ? 문자를 포함한 모든 쿼리스트링 전문
- hash : # 주소 문자열 뒤의 값 .
- 주로 History API가 지원되지 않는 구형 브라우저에서 클라이언트 라우팅을 사용할 때 쓰는 해시 라우터에서 사용
- state : 페이지로 이동할 때 임의로 넣을 수 있는 상태 값
- key : location 객체의 고유 값입니다. 초기에는 default이며, 페이지가 변경될 때마다 고유의 값이 생성됩니다.
쿼리스트링의 파싱
- 쿼리스트링의 값을 파싱하기 위해서는 원래 npm qs 혹은 querystring 패키지를 설치하여 파싱했었습니다.
- 그러나, 리액트 라우터에서는 v6 이후부터 useSearchParams라는 Hook를 통해서 쿼리스트링을 쉽게 다룰 수 있게 되었습니다.
- 아래의 소스코드 참고!
import { useSearchParams } from "react-router-dom";
const UseSearchParamComp = () => {
const [searchParams, setSearchParams] = useSearchParams();
const detail = searchParams.get("detail");
const mode = searchParams.get("mode");
const onToggleDetail = () => {
setSearchParams({ mode, detail: detail === "true" ? false : true });
};
const onIncreaseMode = () => {
const nextMode = mode == null ? 1 : parseInt(mode) + 1;
setSearchParams({ mode: nextMode, detail });
};
return (
<>
<div className="comp func-comp route-comp">
<h1>useSearchParam 테스트</h1>
<p> detail : {detail}</p>
<p> mode : {mode}</p>
<button onClick={onToggleDetail}> onToggleDetail</button>
<button onClick={onIncreaseMode}> mode +1 </button>
</div>
</>
);
};
export default UseSearchParamComp;


중첩된 라우트와 outlet
- 게시글 목록에서 게시글로 이동했는데, 이동하기 전의 게시글 목록 등을 보고자 할 때,
- 공통된 헤더 메뉴바 등을 사용할 때 응용 가능합니다.
- 단, 라우트 태그를 무조건 중첩하여 작성한다고 되는 것이 아니라 <outlet /> 태그도 같이 사용해 주어야 게시글 이동해도 목록이 보이는 등의 화면 구성이 가능합니다.
중첩 라우트와 oulet을 사용한 게시글 과 게시글 목록 같이 보기
import { NavLink, Link, Outlet } from "react-router-dom";
const Articles = () => {
const articleStyle = {
color: "green",
fontSize: 24,
};
const numbers = [1, 2, 3];
const LinkList = numbers.map((number) => (
<li>
<Link to={`/articles/${number}`}>게시글 {number}</Link>
</li>
));
return (
<>
<div className="comp func-comp route-comp">
<Outlet />
<ul>{LinkList}</ul>
</div>
</>
);
};
export default Articles;
- 게시글 목록을 핸들링 할 컴포넌트 페이지 (Articles.js)
import { useParams } from "react-router-dom";
const Article = () => {
const { id } = useParams();
return (
<>
<h1>게시글 {id}</h1>
</>
);
};
export default Article;
- 실제 게시글을 렌더링 할 컴포넌트 페이지 (Article.js)
import "./App.css";
import "./asset/Custom.css";
import "./asset/Router.css";
import { useState } from "react";
import { Route, Routes, Link } from "react-router-dom";
// 컴포넌트 삽입
import HomeComp from "./components/HomeComp";
import AboutComp from "./components/AboutComp";
import ProfileComp01 from "./components/ProfileComp01";
import ProfileComp02 from "./components/ProfileComp02";
import UseSearchParamComp from "./components/UseSearchParamComp";
// 중첩 라우트용 리스트
import Article from "./components/pages/Article";
import Articles from "./components/Articles";
// Layout
import Layout from "./Layout";
// not Found
import NotFoundComp from "./components/NotFoundComp";
// 로그인 창
import LoginComp from "./components/LoginComp";
// 마이페이지
import MyPageComp from "./components/MyPageComp";
const App = () => {
const [name] = useState("Router");
const names = ["jo", "lee", "hey"];
const linkList = names.map((name) => (
<Link to={`/profiles/${name}`} element={ProfileComp01}>
{name}
</Link>
));
return (
<>
<div className="main-header">
<p>
React의 <span>{name}</span> 에 대해 알아보기
</p>
</div>
<div className="header-menu">
<Link to="/">홈</Link>
<Link to="/about">소개</Link>
{linkList}
<Link to="/profiles/comp02">쿼리스트링</Link>
<Link to="/profiles/us-comp01">쿼리스트링-파싱</Link>
<Link to="/articles">글목록</Link>
<Link to="/hello/world">404 페이지 이동</Link>
<Link to="/login">로그인</Link>
<Link to="/my-page">마이페이지</Link>
</div>
<Routes>
{/* <Route path="/" element={<HomeComp />} /> */}
{/* <Route index element={<HomeComp />} />{" "}
<Route path="/about" element={<AboutComp />} /> */}
{/* URL 파라미터로 링크 형성 */}
<Route element={<Layout />}>
<Route path="/" element={<HomeComp />} />
<Route path="/about" element={<AboutComp />} />
<Route path="/profiles/:username" element={<ProfileComp01 />} />
<Route path="/profiles/comp02" element={<ProfileComp02 />} />
<Route path="/profiles/us-comp01" element={<UseSearchParamComp />} />
<Route path="/articles" element={<Articles />}>
<Route path=":id" element={<Article />} />
</Route>
<Route path="*" element={<NotFoundComp />} />
<Route path="/login" element={<LoginComp />} />
<Route path="/my-page" element={<MyPageComp />} />
</Route>
</Routes>
</>
);
};
export default App;
- App.js

NavLink
- Link 태그에 동적 스타일 속성이 추가된 태그입니다.
- 선택된 태그에 대하여 자동으로 전용 CSS 속성을 부여 가능합니다.
import { NavLink, Link, Outlet } from "react-router-dom";
const Articles = () => {
const articleStyle = {
color: "green",
fontSize: 24,
};
const numbers = [1, 2, 3];
const NavLinkList = numbers.map((number) => (
<li>
<NavLink to={`/articles/${number}`} style={({ isActive }) => (isActive ? articleStyle : undefined)}>
게시글 {number}
</NavLink>
</li>
));
return (
<>
<div className="comp func-comp route-comp">
<Outlet />
<ul>{NavLinkList}</ul>
</div>
</>
);
};
export default Articles;

NotFound
- 존재하지 않는, 알 수 없는 주소로 사용자가 접근하려고 할 경우에 표시할 페이지를 구성 가능합니다.
- 404 오류에 전용적으로 사용 가능하며 서버 오류에 대한 페이지 구성은 별도로 구상해야 합니다.
- 라우터 태그의 path 속성에 * 링크를 넣은뒤 element 속성에 404 전용 컴포넌트를 할당해주면 됩니다.
const NotFoundComp = () => {
return (
<>
<div className="comp func-comp route-comp">
<h1>404 NOT FOUND</h1>
<p>페이지를 찾을 수 없습니다.</p>
</div>
</>
);
};
export default NotFoundComp;


Navigate 태그
- 조건에 따라서 화면을 programmatically 하게 렌더링 해야할 경우 사용됨
- 로그인을 안하면 마이페이지를 못보게 하는 등의 조건 설정에 용이합니다.
import { useState } from "react";
import { Navigate } from "react-router-dom";
const LoginComp = () => {
const [text, setText] = useState("");
const [login, setLogin] = useState(false);
const handleKeyDown = (e) => {
if (e.key === "Enter") {
if (e.target.value) {
alert("로그인 되었습니다.!");
setText("");
setLogin(true);
}
}
};
const handleOnChange = (e) => {
setText(e.target.value);
};
if (login) {
return <Navigate to="/my-page" replace={true} />;
}
return (
<>
<div className="comp class-comp login-comp">
<span>ID : </span>
<input placeholder="아이디를 입력해주세요" value={text} onKeyDown={handleKeyDown} onChange={handleOnChange} />
<p>입력 값 : {text}</p>
</div>
</>
);
};
export default LoginComp;
→ LoginComp.js
import { Navigate } from "react-router-dom";
const MyPageComp = ({ log }) => {
if (!log) {
return <Navigate to="/login" replace={true} />;
}
return <div>마이페이지</div>;
};
export default MyPageComp;
→ MyPageComp.js
- 현재는 로그인 했으면 마이페이지 / 안했으면 로그인 기능이 실제 구현된 것은 아님
- props로 boolean 값을 주어 페이지 표시할 지 안 할 지 결정 가능한데 부모 컴포넌트에서 수동으로 값을 변경해주어야 함!
import "./App.css";
import "./asset/Custom.css";
import "./asset/Router.css";
(... 중략 ...)
const App = () => {
(... 중략 ...)
return (
<>
<div className="main-header">
<p>
React의 <span>{name}</span> 에 대해 알아보기
</p>
</div>
<div className="header-menu">
(... 중략 ...)
</div>
<Routes>
<Route element={<Layout />}>
(... 중략 ...)
<Route path="/login" element={<LoginComp />} />
<Route path="/my-page" element={<MyPageComp />} />
</Route>
</Routes>
</>
);
};
export default App;
→ App.js

'프론트엔드(Front-End) > React' 카테고리의 다른 글
[REACT] Immer와 불변성 (0) | 2023.01.13 |
---|---|
[REACT] Context API (2) | 2023.01.10 |
[REACT] 리액트와 훅(HOOK) (0) | 2023.01.08 |
[REACT] 리액트의 라이프사이클(LifeCycle) (0) | 2023.01.07 |
[REACT] 컴포넌트 요소의 반복(map, filter) (1) | 2023.01.06 |