리액트 라우터
각각의 url에 따라 선택된 데이터를 하나의 페이지에서 렌더링 해주는 라이브러리
SPA(Single Page Application)에서 새로운 페이지를 로드하지 않고
하나의 페이지 안에서 필요한 컴포넌트만 가져와서 다른 페이지를 나타내는 방식을 지원.
*라우팅 : 사용자가 요청한 url에 따라 해당 url에 맞게 페이지를 보여주는 것
이전 MPA(Multiple Page Application)에서는 새로운 페이지를 로드하며 페이지를 이동하는 방식
<a href="sub.html"> 서브페이지 </a>
1) 라우터 설치하기
npm install react-router-dom
2) 라우터 사용하기
1. 상위 컴포넌트에서 라우터를 적용 → <BrowserRouter> 컴포넌트
ex>
<BrowserRouter>
<App></App>
</BrowserRouter>
2. 경로에 따라 보일 component를 설정 <Routes><Route> 컴포넌트
Routes컴포넌트는 여러 Route를 감싸서 그중 url이 일치하는 라우트 단 하나만 렌더링 시켜줌
Route는 path속성에 경로, element속성에 컴포넌트를 지정
<Routes>
<Route path="경로" element={<component /> } /> //path가 일치하면 element에 있는 컴포넌트를 렌더링함
<Route path="경로" element={<component /> } />
</Routes>
예제)
우선은 주소로 이동했을 때 보여줄 페이지를 만들어 주자 pages폴더를 만들어서 폴더 안에서 관리해 준다.
Home.js
import React from "react";
import { Link } from "react-router-dom";
const Home = () => {
return (
<div>
<h2>홈</h2>
<p>가장 먼저 보여지는 페이지입니다.</p>
<Link to="/product">제품페이지</Link>
</div>
);
};
export default Home;
Home은 기본주소일 때 보여줄 거 기 때문에 <Router path=' ' element={<Home/>}/>으로
App에 넣어주면 된다.
홈에서는 제품페이지로 이동할 수 있는 링크가 있고 링크 주소는 해당주소에서 /product로 이동한다.
Product.js
import React from "react";
import { Link } from "react-router-dom";
const Product = () => {
return (
<div>
<h2>제품페이지</h2>
<p>제품페이지입니다</p>
<Link to="/">홈</Link>
</div>
);
};
export default Product;
Product는 링크를 타고 /product로 이동했을 때 렌더링되도록
<Router path='/product' element={<Product/>}/>으로 App에 넣어 준다.
Product에서 다시 홈으로 돌아갈 수 있도록 링크를 달아주었다.
App.js
import "./styles.css";
import { Route, Routes } from "react-router-dom";
import Home from "./pages/Home";
import Product from "./pages/Product";
export default function App() {
return (
<div className="App">
<Routes>
<Route path="" element={<Home />} />
<Route path="/product" element={<Product />} />
</Routes>
</div>
);
}
Routes안에 Route들을 넣어주면 안에서 Path조건에 맞는 한 개의 Route만 렌더링 된다.
그리고 꼭 까먹지 말고 상위컴포넌트를 BrowserRouter로 감싸줘야 한다.
index.js
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(
<StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</StrictMode>
);
URL 파라미터와 쿼리 스트링 (주소창에 데이터 전송)
페이지 주소를 정의할 때 가끔은 변하는 유동적인 값을 사용해야 할 때도 있다.
1 ) URL 파라미터 예시
Link에서 value를 전달
<Link to='/product/item1'> //
Route에서 키를 전달
<Route path='/product/:productname' element={<Product></Product>}/>
useParams( ); --> 객체를 리턴 // 해당주소가 들어가는 컴포넌트에서 값을 받음 아래의 객체를 리턴함
{
productname:item1
}
Product.js
import React from 'react';
import { Link, useParams } from 'react-router-dom';
const data= {
item1:{
title:"아이폰",
price: "150만원",
desc:"비싸요 예뻐요"
},
item2:{
title:"갤럭시",
price:"30만원",
desc:"싸고 예뻐요"
}
}
const Product = () => {
const {productname} = useParams(); //객체를 리턴 {productname:'item1'}
const product = data[productname]
return (
<div>
<h2>제품페이지</h2>
<p>제품페이지 입니다.</p>
{product ? <div>
<h3>{product.title}</h3>
<p>{product.price}</p>
<p>{product.desc}</p>
</div>:<p>존재하지 않는 페이지입니다.</p>}
</div>
);
};
export default Product;
Product에 data객체를 하나 만들어주고 useParams( )로 받아온 값을 data객체의 key값으로 넣어서
필요한 값을 받아왔다.
두 개의 값 중에 선택해서 받을 수 있도록 링크를 하나 더 만들어주자.
링크하나는 product/item1로 이동하고
두 번째는 product/item2로 이동하게 만들어준다.
2) 쿼리스트링 예시
<Link to='/about?name=green&age=30'>About</Link>
useLocation( ) => 객체 리턴 location객체랑 똑같이 나옴
. search로 접근 ?name=green&age=30이렇게 나옴
useSearchParams( ) 배열을 리턴해줌--> [searchParams, setSearchParams]
searchParams.get("받아온 키값") //name, age
About.js
import React from "react";
import { useLocation, useSearchParams } from "react-router-dom";
const About = () => {
const location = useLocation();
const [searchParams, setParams] = useSearchParams();
const name = searchParams.get("name");
const age = searchParams.get("age");
console.log(location);
return (
<div>
<h2>소개페이지</h2>
<p>소개페이지 입니다.</p>
<p>{location.search}</p>
<p>name값은{name}</p>
<p>age값은{age}</p>
</div>
);
};
export default About;
쿼리스트링을 받을 페이지로 About컴포넌트를 만들어줬다. 쿼리스트링값을 두 가지 방법으로 받는데
useLocation과
useSearchParams로 받았다.
useLocation 은 location 객체를 받아주고
useSearchParams는 location에서 search를 따로따로 떨어트려서 반환해 준다 반환해 준 값은. get(키값)
중첩된 루트 <outlet/>
app --> subpage --> subpage1
subpage2
subpage3
subpages 안에 subpage를 넣어주고 subpage컴포넌트 리턴 부분에 outlet을 넣어줌
<Route path='/subpages' element={<Subpages/>}>
<Route path='/subpages/:id' element={<Subpage/>}/>
</Route>
return (
<div>
<li><NavLink to='/subpages/1'
style={({isActive})=> isActive? activeStyle:undefined}
>서브페이지1</NavLink></li>
<li><NavLink to='/subpages/2'
style={({isActive})=> isActive? activeStyle:undefined}
>서브페이지2</NavLink></li>
<li><NavLink to='/subpages/3'
style={({isActive})=> isActive? activeStyle:undefined}
>서브페이지3</NavLink></li>
<Outlet/>
</div>
);
예제)
우선은 링크가 많아지니 링크를 모아서 header컴포넌트에 넣어주도록 하겠다
Header.js
import React from "react";
import { Link } from "react-router-dom";
const Header = ({ sitename }) => {
return (
<div>
<h1>{sitename}</h1>
<ul>
<li>
<Link to="/">home</Link>
</li>
<li>
<Link to="/about?name=green&age=30">About</Link>
</li>
<li>
<Link to="/product/item1">iphone</Link>
</li>
<li>
<Link to="/product/item2">galaxy</Link>
</li>
<li>
<Link to="/subpages">서브페이지</Link>
</li>
</ul>
</div>
);
};
export default Header;
각 페이지로 이동하는 링크들을 모두 헤더에 넣어주고 h1태그에는 Props로 이름을 받아와서 넣어준다.
Subpages.js
import React from "react";
import { Link, Outlet } from "react-router-dom";
const Subpages = () => {
return (
<div>
<li>
<Link to="/subpages/1">서브페이지1</Link>
</li>
<li>
<Link to="/subpages/2">서브페이지2</Link>
</li>
<li>
<Link to="/subpages/3">서브페이지3</Link>
</li>
<Outlet />
</div>
);
};
export default Subpages;
subpages에서 각 서브페이지로 이동할 수 있는 링크를 만들고 서브페이지가 렌더링 되면 subpages내부에 렌더링 되기 때문에 <Outlet/>을 써서 보여준다.
Subpage.js
import React from "react";
import { useParams } from "react-router-dom";
const Subpage = () => {
const { id } = useParams();
return (
<div>
<h2>서브페이지{id}</h2>
</div>
);
};
export default Subpage;
보내주는 url값을 useParams로 받아서 id에 할당해 주고 h2태그에 넣어준다.
App.js
import "./styles.css";
import { Route, Routes } from "react-router-dom";
import Home from "./pages/Home";
import Product from "./pages/Product";
import About from "./pages/About";
import Header from "./components/Header";
import Subpage from "./pages/Subpage";
import Subpages from "./pages/Subpages";
export default function App() {
return (
<div className="App">
<Header sitename="green" />
<Routes>
<Route path="" element={<Home />} />
<Route path="/product/:productname" element={<Product />} />
<Route path="/about" element={<About />} />
<Route path="/subpages" element={<Subpages />}>
<Route path="/subpages/:id" element={<Subpage />} />
</Route>
</Routes>
</div>
);
}
Route subpages 태그 안에 Route Subpage를 넣어주었다. 이렇게 해주면
Route subpages가 렌더링 될 때 subpages도 조건이 일치하면 같이 렌더링 될 수 있다. (Outlet 써줘야 함)
useNavigate( )
Link컴포넌트를 사용하지 않고 다른 페이지로 이동을 해야 할 때 사용하는 Hook
const navigate = useNavigate();
navigate(-1) //이전페이지로 이동
navigate(1) //다음페이지로 이동
navigate('/product') 경로로 이동
Header.js
import React from "react";
import { Link, useNavigate } from "react-router-dom";
const Header = ({ sitename }) => {
const navigate = useNavigate();
const goback = () => {
//이전페이지 이동
navigate(-1);
};
const goSubpage = () => {
//서브페이지 이동
navigate("/subpages");
};
return (
<div>
<h1>{sitename}</h1>
<ul>
<li>
<Link to="/">home</Link>
</li>
<li>
<Link to="/about?name=green&age=30">About</Link>
</li>
<li>
<Link to="/product/item1">iphone</Link>
</li>
<li>
<Link to="/product/item2">galaxy</Link>
</li>
<li>
<Link to="/subpages">서브페이지</Link>
</li>
</ul>
<div>
<button onClick={goback}>뒤로가기</button>
<button onClick={goSubpage}>subpage</button>
</div>
</div>
);
};
export default Header;
useNavigate를 navigate변수에 할당해 주고 이전페이지로 이동하는 함수와 서브페이지로 이동하는 함수를 만들어서 버튼에 클릭이벤트로 넣어주었다.
<NavLink> 컴포넌트
링크에서 사용하는 경로가 현재 라우트의 경로와 일치하는 경우 특정 스타일 또는
css클래스를 적용하는 컴포넌트
<NavLink> 컴포넌트를 사용할 때에는 style 또는 className을 설정할 때
{isActive:boolen}을 파라미터로 전달받는 함수 타입의 값을 전달함.
ex>
const activeStyle={
backgroundColor:'pink',
fontSize: 24
}
<NavLink style = {({isActive})=> isActive? activeStyle : undefined }/>
<NavLink className = {({isActive})=> isActive? "active" : undefined }/>
Subpages.js
import React from "react";
import { NavLink, Outlet } from "react-router-dom";
const Subpages = () => {
const activeStyle = {
backgroundColor: "pink",
fontSize: 24
};
return (
<div>
<li>
<NavLink
to="/subpages/1"
style={({ isActive }) => (isActive ? activeStyle : undefined)}
>
서브페이지1
</NavLink>
</li>
<li>
<NavLink
to="/subpages/2"
style={({ isActive }) => (isActive ? activeStyle : undefined)}
>
서브페이지2
</NavLink>
</li>
<li>
<NavLink
to="/subpages/3"
style={({ isActive }) => (isActive ? activeStyle : undefined)}
>
서브페이지3
</NavLink>
</li>
<Outlet />
</div>
);
};
export default Subpages;
서브페이지를 링크를 클릭하면 클릭한 링크의 isActive가 true가 되면서 스타일 이 적용된다.
NotFound 페이지 만들기
미리 정의되지 않는 경로에 사용자가 진입했을 때.
보이는 페이지 페이지를 찾을 수 없을 때 나타나는 페이지
NotFound.js
import React from 'react';
const NotFound = () => {
return (
<div>
404<br/>
페이지를 찾을 수 없습니다
</div>
);
};
export default NotFound;
<Route path="*" element={<Notfound/>}/>
예제)
리액트라우터 라이브러리는 페이지를 이동해줘야 하는 웹의 특성상 필수로 알아둬야 하고 또 잘 쓸 수 있어야 할 것 같다. 확실히 링크를 타고 다른 페이지로 이동되는 웹사이트보다 같은 페이지에서 계속 렌더링 시켜주는 방식이 화면전환이 더 깔끔하고 부드러워 보인다.
'프론트엔드 정복기 > 리액트' 카테고리의 다른 글
[React]22 리액트쇼핑몰만들기ver0.1 (서버에서 상품정보받아오기) (0) | 2023.01.20 |
---|---|
[React]21 서버만들기(node.js/express프레임워크/node + mysql) (0) | 2023.01.19 |
[React]19 아이콘 컴포넌트 (react-icons) (0) | 2023.01.18 |
[React]18 (axios) (0) | 2023.01.18 |
[React]17 상태관리2(useReducer) (0) | 2023.01.17 |