[React] 리액트 라우터v6
SPA란
Single Page Application
의 약자.
전통적인 웹페이지
사용자의 브라우저가 request
를 던지고 -> 서버에서 response
로 필요한 html
을 사용자의 브라우저에 전달 -> 브라우저가 이를 해석해 사용자에게 렌더링
이런 절차를 반복했는데, 서버측에서 html을 전달할때, 사전에 만들어서 제공하거나, 필요한 데이터에따라 유동적으로 제공하는 pug
라는 템플릿 엔진을 사용하기도 했다.
이런 렌더링의 문제점은 새로운 화면을 보여줄때마다 서버측에서 모든 뷰를 준비해야한다면, 성능상의 문제가 생긴다는 것이다.
특히 최근에는 사용자와의 인터렉션이 많아졌기 때문에 이런 방식은 비효율적이다.
프레임워크나 라이브러리 사용하기
리액트 라이브러리나 뷰와같은 프레임워크를 사용해 필요한 부분만 자바스크립트 파일로 업데이트 해주는 방식이 생겼다.
혹은, 새로운 데이터가 필요하다면 서버API를 호출해 필요한 데이터만 새로 불러와 어플리케이션에서 사용할수도 있다.
SPA는 브라우저에게 제공하는 Html은 한 개이지만(index.html) 해당 페이지에서 로딩된 자바스크립트와 브라우저 주소에 따라 다른 화면을 보여줄 수 있다.
이렇게 다른 주소에 다른 렌더링을 하는 것을 라우팅
이라고 하는데, 리액트를 라우팅할땐
리액트 라우터
, 리치 라우터
, Next.js
등 여러가지를 사용할 수 있다.
SPA의 단점
SPA의 단점으로 앱의 규모가 커지면 자바스크립트 파일이 너무 커진다는 것이다.
페이지 로딩시에, 실제로 사용자가 방문하지 않는 페이지의 스크립트도 불러오기 때문이다.
이런 문제점은 코드 스플리팅
으로 라우트별로 파일을 나눠 트래픽과 로딩속도를 개선할 수 있다.
또한 자바스크립트로 라우팅을 관리하면, 자바스크립트를 실행하지 않는 일반 크롤러에서 페이지의 정보를 제대로 수집하지 못한다.
그리고 자바스크립트가 로딩이 완료되고 실행되기까지 시간동안 페이지에 아무것도 나타나지 않을 수 있다는 문제점도 있다.
이런 문제점은 서버 사이드 렌더링
을 통해 해결할 수 있다.
라우터 적용,사용법
yarn add react-router-dom
<2021-12-14 현재시점 기준, 최신버전으로 깔면 “react-router-dom”: “^6.1.1”>버전이 설치된다.
책의 react-router버전과 최신버전이 다르기때문에 (공식문서)[https://reactrouter.com/docs/en/v6]를 참고해가면서 공부해보려한다.
BrouserRouter
리액트 프로젝트에 리액트 라우터를 적용하기 위해선 src/index.js 파일에서 react-router-dom 에 내장된 BrowserRouter라는 컴포넌트를 사용해 감싸면된다.
이 컴포넌트는 HTML5의 History API를 사용해 페이지를 새로고침하지 않고도 주소를 변경하고, 현재 주소에 관련된 정보를 props로 쉽게 조회하거나 사용할 수 있게 해준다.
(History API 참고)[https://www.zerocho.com/category/HTML&DOM/post/599d2fb635814200189fe1a7]
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
페이지 생성
브라우저에 특정 주소를 입력하면 보여줄 화면을 만든다.
import React from "react";
const Home = () => {
return (
<div>
<h1>홈</h1>
<p>이거 홈페이지임요</p>
</div>
);
};
export default Home;
import React from "react";
const About = () => {
return (
<div>
<h1>소개</h1>
<p>자기소개임요</p>
</div>
);
};
export default About;
페이지 연결
import React from "react";
import Home from "./Home";
import About from "./About";
import { Route, Routes } from "react-router-dom";
function App() {
return (
<div className="App">
<Route path="/" component={Home} />
<Route path="/about" component={About} />
</div>
);
}
export default App;
이렇게 하고 출력하면
고생길오픈
Error: A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.
직역하면, <Route>
는 반드시 <Routes>
의 자식으로 사용되어야 한다는 것 같다.
감싸주자.
import React from "react";
import Home from "./Home";
import About from "./About";
import { Route, Routes } from "react-router-dom";
function App() {
return (
<div className="App">
<Routes>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
</Routes>
</div>
);
}
export default App;
실행하면,
!@#$!@#$
직역하면, leaf route에서 element가 없단다.
구글링해보니, 스택 오버플로우에 같은 이슈로 글이 올라왔다.
In V6, you can’t use the component prop anymore. It was replaced in favor of element:
<Route path="/" element={<Home />}></Route>
V6으로 바뀌면서 Route에 컴포넌트를 할당하는 방식이
<Route path="/" component={Home} />
<Route path="/about" component={About} />
요고에서
<Route path="/" element={<Home/>} />
<Route path="/about" element={<About/>} />
이렇게 바뀌셨단다.
좀 더 직관적으로 보이는 것 같다.
!!원래 책에선 exact={true}
를 Home Route에 넣었지만, V6에서는 사라졌다고한다.!!
Link to 컴포넌트로 다른 주소로 이동하기
리액트에서는 a태그를 사용하면 안된다.
a태그를 사용해 다른 주소로 이동하면 컴포넌트들이 다시 렌더링되면서 기존 state들이 모두 날라가게된다.
그래서 리액트에서는 link
컴포넌트를 사용한다.
link
컴포넌트는 애플리케이션은 유지한 상태에서 HTML5 History API를 사용해 페이지의 주소만 변경해준다.
<Link to="주소">내용</Link>
그대로 navigation바를 만들어보자.
import React from "react";
import Home from "./Home";
import About from "./About";
import { Link, Route, Routes } from "react-router-dom";
function App() {
return (
<div className="App">
<div className="nav">
<ul>
<li>
<Link to="/">홈</Link>
</li>
<li>
<Link to="about">소개</Link>
</li>
</ul>
</div>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</div>
);
}
export default App;
Route 하나에 여러개 경로 설정
<Route path="/about" element={<About />} />
<Route path="/info" element={<About />} />
경로의 path props만 수정하면 된다.
URL 파라미터, 쿼리
페이지 주소에 유동적인 값을 전해야 할 때도 있다.
일반적으로 파라미터는 특정 아이디, 이름을 사용해 조회할 때 사용하고,
쿼리는 특정 키워드를 검색하거나 페이지에 필요한 옵션을 전달할 때 사용한다.
URL 파라미터
import React from "react";
const DATA = {
LightBig: {
name: "강명환",
description: "리액트 공부중",
},
Velopert: {
name: "김민준",
description: "저자",
},
};
const Profile = ({ match }) => {
const { username } = match.params;
const profile = DATA[username];
if (!profile) {
return <div>존재하지 않는 사용자입니다.</div>;
}
return (
<div>
<h3>
{username}({profile.name})
</h3>
<p>{profile.description}</p>
</div>
);
};
export default Profile;
또 오류가 난다.
삽질 스따뜨
오류가 뭘까 하고 console.log(match)
를 해보니 undefined
값이 출력된다.
그 이유인 즉슨 v6에서 match는 사라졌다.
공식문서에서는 useParams
훅을 사용하라고한다. 아래는 공식문서의 코드
import { useParams } from "react-router-dom";
export default function Invoice() {
let params = useParams();
return <h2>Invoice: {params.invoiceId}</h2>;
}
import { useParams } from "react-router-dom";
훅을 import 해주고,
const DATA = {
LightBig: {
name: "강명환",
description: "리액트 공부중",
},
Velopert: {
name: "김민준",
description: "저자",
},
};
const Profile = () => {
let params = useParams();
const Username = params.username; //외부객체
const profile = DATA[Username]; //내부객체
if (!profile) {
return <div>존재하지 않는 사용자입니다.</div>;
}
return (
<div>
<h3>
{Username}({profile.name})
</h3>
<p>{profile.description}</p>
</div>
);
};
export default Profile;
let params = useParams()
로 파라미터 객체를 선언하면 컴포넌트 내부에서 URL 파라미터를 사용할 수 있다.
URL 쿼리
(MDN location 설명)[https://developer.mozilla.org/en-US/docs/Web/API/Location]
URL 쿼리에 대해 알기 전에, WEB API 중 location에 대해 먼저 알아야한다.
Location
은 객체가 연결된 경로,(URL)을 객체로 나타낸다.
리액트 라우터에서 location 객체를 사용하기 위해선 useLocation
훅을 사용해야한다.
훅을 사용하면, useEffect
를 사용해 location이 바뀔때마다 side effect를 만들 수 있다!!
import * as React from 'react';
import { useLocation } from 'react-router-dom';
function App() {
let location = useLocation();
React.useEffect(() => {
ga('send', 'pageview');
}, [location]);
return (
// ...
);
}
import qs from "qs";
import React from "react";
import { useLocation } from "react-router-dom";
const About = () => {
const seemylocation = useLocation();
console.log(seemylocation);
const query = qs.parse(useLocation().search, { ignoreQueryPrefix: true });
console.log(query);
const ShowDetail = query.detail === "true";
return (
<div>
<h1>소개</h1>
<p>자기소개임요</p>
{ShowDetail && <p>현재 detail값은 true입니다.</p>}
</div>
);
};
export default About;
http://localhost:3000/about?detail=false
이 주소로 접속해보자.
콘솔창에 seemylocation
객체는
{
"pathname": "/about",
"search": "?detail=false",
"hash": "",
"state": null,
"key": "default"
}
query객체는
{ "detail": "false" }
이렇게 리턴되는 것을 볼 수 있다.
location객체가 여러가지의 키값을 가질 수 있다는 점,
그리고 search
키값은 ?
뒤의 문자열을 가져올 수 있다는 걸 배웠다.
search값에서 특정 값을 읽어오기 위해서는 이 문자열을 객체형태로 반환해야한다.
이때 사용하는 것이 qs라이브러리이다.
yarn add qs
qs를 사용할때 ignoreQueryPrefix: true
설정을 덮어씌우면 파싱할때 쿼리의 초기설정을 무시할 수 있다.
search객체는 ?로 시작하는 주소를 가져오니까, ?를 생략해준다는 의미이다.
서브라우트
서브라우트는 라우트 내부에 다른 라우트를 정의하는 것을 의미한다.
프로필을 누르면 -> username 나타나도록하고, -> 그 유저의 정보가 나타나는 루트를 정의한다.
현재 프로필들을 나타내는 컴포넌트를 만든다. Profiles.js
import React from "react";
import { Link, Route, Routes } from "react-router-dom";
import Profile from "./Profile";
const Profiles = () => {
return (
<div>
<h3>사용자목록:</h3>
<ul>
<li>
<Link to="velopert">저자</Link>
</li>
<li>
<Link to="lightbig">강명환</Link>
</li>
</ul>
<Routes>
<Route path="" element={<div>사용자를 선택하세요</div>}></Route>
<Route path=":username" element={<Profile />}></Route>
</Routes>
</div>
)
}
export default Profiles;
이전에 Route를 정의하기전에 Routes
로 감싸줬었다.
현재 경로에서 새로운 Route
를 정의하기 위해선 반드시 Routes
태그로 감싸줘야한다.
그리고 상위 라우트인 App.js도 수정해줘야한다.
<Routes>
<Route
path="*"
element={
<main style=>
<p>There's nothing here!</p>
</main>
}
/>
<Route path="" element={<Home />} />
<Route path="about" element={<About />} />
<Route path="info" element={<About />} />
<Route path="profiles/*" element={<Profiles />} />
</Routes>
현재 App에서 Route를 정의하고 있는데, 리액트 라우터는 Routes
를 어디서든 사용할 수 있다.
단, 이렇게 할 경우, 상위경로의 끝에 *
을 넣어주어야 상위경로로부터 지속적으로 라우팅하고 있다는 걸 알려줄 수 있다.
뒷장부터 history
에 대해 다루고있는데, 구글링 결과… v6가 현재 여러가지 issue를 발생시키고 있다고한다.
useHistory가 useNaviagtor로 바뀌고, Link 경로가 상대경로가 되는 등 이슈를 가지고 있는데,,,
뒷장부터는 @5.3.0
으로 공부해보려한다.
앞장도 복습해보자…
댓글남기기