React Router를 사용하면 새로운 페이지를 로드하지 않고 하나의 페이지 안에서 필요한 데이터만 가져오는 형태를 가지기 때문에 불필요한 렌더링을 막을수 있다.
1) 라우팅(Routing)이란 ?
웹을 사용할 때 전통적인 링크 연결방식은 HTML에서 <a> 태그를 사용하여 href 속성에 연결할 링크를 넣어주는 방식입니다.
이러한 방식은 웹사이트의 규모가 크지 않을 때는 사용하는데 크게 불편함이 없지만 로드되는 컨텐츠나 페이지의 용량자체가 크다면 불편함을 초래할 수 있습니다.
애초에 링크로 연결되는 방식은 각각의 HTML 파일을 로드하는 것이기 때문에 새로운 페이지로 이동할 때마다 새로고침이 발생할 것이며 해당 페이지 자체 또는 로드할 컨텐츠의 용량이 크다면 사용자 입장에서는 불만이 생길 수 밖에 없을 것입니다.
(페이스북이나 인스타그램처럼 퓨어 텍스트보다 압도적으로 높은 용량의 이미지/영상 컨텐츠가 주를 이루는 페이지일수록 더 심해짐)
그래서 SPA(Single Page Application)이라는 수단이 도입되었으며, 이는 페이지를 로드하면서 페이지 내부의 모든 구성요소를 렌더링 하는 것이 아니라 페이지를 이동하면서 바뀌는 부분만 렌더링 하는 것입니다.
먼저 SPA라 하더라도 한 개의 페이지만 사용하는 것은 아닙니다. Header, Navigator, Footer 처럼 중복되는 컴포넌트를 제외하더라도 사용자 정보, 컨텐츠 정보, 컨텐츠 세부정보 등의 컴포넌트들의 페이지 주소를 다르게 구성해야 할 필요가 있습니다.
주소에 따라 서로 다른 컴포넌트들의 배치를 변경하는 작업을 라우팅(Rounting)이라고 합니다. 즉, 경로(주소)에 따라서 컴포넌트를 변경하는 과정에서 데이터가 출발점에서 도착점 까지 도착할 수 있는 경로들을 구성하는 작업을 의미합니다.
React에서는 자체적으로 Router 기능이 포함되어 있지 않습니다. 개발자가 주소별로 다른 컴포넌트를 Display 해야 하는 번거로움이 있습니다.
👉🏻 React SPA Router를 위해 가장 많이 사용하는 외부 모듈이 바로 React Router !
2) React Router 설치
// React Router Install
$ npm install react-router-dom
// 특정 버전 React-Router Install
$ npm install react-router-dom@6.3.0
ReactRouter를 사용하기 위해서는 먼저 npm을 이용해 설치를 해줘야 합니다.
그리고 react-router-dom 모듈 안에 있는 <Link /> 모듈과 <BrowserRouter />, <Routes />, <Route /> 모듈을 사용해서 각각을 연결해줍니다.
여기에서 Link 태그는 기존의 a 태그 역할을 할 것이며, BrowserRouter, Routes, Route는 Link 태그에 부여된 to 속성의 값을 따라 각각 다른 컴포넌트를 보여주게 됩니다.
3) React Router 주요 컴포넌트
🚨 react-router-dom v6 에서는 더이상 Switch 모듈을 사용하지 않습니다. 대신 Routes 모듈을 사용합니다.
React Router는 크게 3가지 기능을 담당합니다. 라우팅 기능과 경로 매칭 기능 그리고 경로 변경 기능을 내장하고 있습니다.
<Router>
<Link/>
<Link/>
<Route />
<Route />
</Router>
<Router> : <Route>와 <Link>컴포넌트가 함께 유기적으로 동작하도록 묶어주는데 사용합니다. <Route>와 <Link> 컴포넌트는 DOM 트리 상에서 항상 <Router>를 공통 상위 컴포넌트로 가져야합니다.(위 예시에서는 BrowserRouter 사용)
<Route path="/about" element={<About/>}/>
<Route><Route> : 현재 주소창의 경로와 매치될 경우에 보여줄 컴포넌트를 지정하는데 사용됩니다. path prop을 통해서 매치시킬 경로를 지정하고 element prop을 통해서 매치되었을 때 보여줄 컴포넌트를 할당합니다.
<Routes>
<Route exact paht="/" element={< Home/>}></Route>
<Route paht="/product1" element={< Product1/>}></Route>
<Route paht="/product2" element={< Product2/>}></Route>
<Route path="/" element={'Not found'}></Route>
</Routes>
v6으로 업데이트 되면서 <Route> 태그들을 <Routes> 태그로 감싸주어야 합니다.
<Link to="/about">About</Link>
<Link> : html의 <a> 태그와 유사한 기능, to prop을 통해서 이동할 경로를 지정해줍니다. 기존 HTML의 <a>태그가 새로고침을 통해 처음부터 렌더링을 수행한다면 <Link> 컴포넌트는 페이지 전환을 방지하는 기능을 내장하고 있습니다. 즉 새로고침을 하지 않더라도 해당 페이지의 소스를 렌더링 하게 됩니다.
4) 실습 및 구현
import { Link, Route, BrowserRouter as Router } from 'react-router-dom'
먼저 React Router 컴포넌트를 사용하기 위해서는 react-router-dom에서 import 해주면 됩니다.
<header>
<Link to="/">
<button>Home</button>
</Link>
<Link to="/about">
<button>about</button>
</Link>
<Link to="/users">
<button>User</button>
</Link>
</header>
Header 부분을 <Link> 컴포넌트를 사용해서 리펙토링 합니다. to prop에 해당 메뉴 클릭 시 이동해야 할 경로를 지정합니다.
<main>
<Route exact path = "/" element={<Home/>} />
<Route path="/about" element={<About/>} />
<Route path="/users" element={<NotFound/>} />
</main>
main 부분은 <Route> 컴포넌트를 사용합니다. path prop에 매치 할 때 비교될 경로를 지정하고, element prop에 매치할 때 보여줄 컴포넌트를 할당합니다.
여기서 <Route> 컴포넌트에만 exact prop이 사용된 이유는 React Router의 디폴트 매칭 규칙 때문입니다.
React Router는 path prop의 경로와 현재 브라우저 주소창의 url 경로(location.pathname)를 비교합니다. 그리고 현재 url 경로 값이 <Route>의 path prop 값과 앞부분만 일치해도 같은것으로 간주합니다.
따라서 path가 / 일 경우 / 뿐만 아니라 / 로 시작하는 모든 url 경로와 매치가 되기 때문에 exact prop 이 없으면 home 컴포넌트가 url 경로와 상관없이 항상 보여지게 됩니다.
하지만 exact prop을 붙여주면 url 경로 값이 <Route>의 path 값과 전체가 일치해야 매치가 일어나고 처리를 해줍니다.
import React from 'react'
import { Link, Route, BrowserRouter as Router } from 'react-router-dom'
import Home from "./Home";
import About from "./About";
import NotFound from "./NotFound";
function App() {
return (
<Router>
<header>
<Link to="/">
<button>Home</button>
</Link>
<Link to="/about">
<button>about</button>
</Link>
<Link to="/users">
<button>User</button>
</Link>
</header>
<hr/>
<main>
<Route exact path = "/" element={<Home/>} />
<Route path="/about" element={<About/>} />
<Route path="/users" element={<NotFound/>} />
</main>
</Router>
);
}
export default App;
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>,
document.getElementById('root')
);
마지막으로 <Router> 컴포넌트를 사용해 전체를 감싸줍니다. 위와 같이 App.js 에서 <Route>와 <Link>전체를 감싸도 되고 index.js 에서<App /> 전체를 감싸도 됩니다.
5) 중첩 라우팅(Nested routes) 사용법
중첩 라우팅이란 서브 페이지를 만든다고도 할 수 있는데 해당하는 페이지에서 조금 더 구체적으로 구분을 지어 화면을 교체(표시) 해줄 필요가 있을 때 사용됩니다.
예를 들면, 쇼핑몰 상세 페이지가 있을 것인데 'myshop/products' 라는 주소로 입력했을 때는 단순히 쇼핑몰에 게시된 상품들이 나열되어 있다고 가정해봅시다.
여러 상품들 중 하나의 상품을 클릭하면 해당하는 상품의 상세 페이지를 보여주고 싶을 때 중첩 라우팅을 사용할 수 있습니다.
위 예시에서 'myshop/products/01'과 같은 URL을 입력했다면 쇼핑몰 상품의 01번째 아이템 페이지가 나타나야 합니다.
<Route path="/about" element={<About />}>
<Route path="location" element={<Location />}></Route>
</Route>
Route 안에 중첩(자식) Route를 작성해서 서브 페이지를 만들어 줄 수 있습니다.
서브 페이지의 path는 / 를 생략하고 작성하며, element는 보여줄 컴포넌트 또는 HTML 태그를 작성해주면 됩니다.
import { Outlet } from 'react-router-dom';
function About() {
return (
<div>
<div>
<h2>여기는 About 페이지입니다.</h2>
<p>대충 쇼핑몰 페이지라는 뜻</p>
</div>
<Outlet />
</div>
);
}
위와 같이 react-router-dom에서 Outlet을 import하고 <Outlet/>으로 부모 라우트의 컴포넌트에서 자식 라우트 컴포넌트의 위치를 지정해주면 중첩 라우팅이 완료됩니다.
5-1) 중첩 라우팅 시 부모 컴포넌트에서 자식 컴포넌트에게 props를 전달하는 방법
// router.tsx
<Route path="/*" element={<Parent/>}>
<Route path="child" element={<Child/>} />
</Route>
// 부모 컴포넌트
…
<Outlet context={{ coinId }} />
…
부모 컴포넌트안에 <Outlet/>으로 원하는 자손 컴포넌트 위치를 정합니다. 그리고 context prop으로 자손 컴포넌트에게에게 넘기고 싶은 값을 넣습니다.
//자손 컴포넌트
import { useOutletContext } from 'react-router-dom';
const {coinId} = useOutletContext();
자손컴포넌트에서 위의<Outlet/>의 context prop을 가지려면 useOutletContext Hook을 사용해야 합니다.
//자손 컴포넌트
import { useOutletContext } from 'react-router-dom';
type ChildProps = {
coinId: string
}
function Child() {
…
const {coinId} = useOutletContext<ChildProps>();
…
}
타입스크립트를 사용한다면 당연히 interface를 선언한 뒤 사용해야 합니다.
( 출처 : https://about-tech.tistory.com/10 , https://velog.io/@goodenough/React-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%9D%BC%EC%9A%B0%ED%84%B0react-router https://velog.io/@reasonz/2022.07.14-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%9D%BC%EC%9A%B0%ED%84%B0-%EC%A4%91%EC%B2%A9-%EB%9D%BC%EC%9A%B0%ED%8C%85-nested-routes-outlet )
'React ⚛️' 카테고리의 다른 글
[React-Router-Dom] useNavigate()와 useLocation()를 활용한 파라미터 전달 및 취득방법 (0) | 2023.02.19 |
---|---|
[React] useParams Hook의 사용법 (0) | 2023.02.14 |
[React] useEffect Hook의 사용법 (0) | 2023.02.12 |
[React] state의 개념과 useState Hook 사용법 (0) | 2023.02.12 |
[React] Life Cycle의 개념 (0) | 2023.02.11 |