이제서야 Hook이 뭔지, Life Cycle이 뭔지 이해한거 같은데 또 새로운 개념이 나왔다...ㅠㅠ 다만 개념을 이해하기 어려웠던 전과 달리 이번건 개념은 쉽고 적용하는게 어려운 것 같다. 쨌든 공부한 걸 정리해보자.
기존의 웹사이트들은 대부분 MPA 방식을 사용했다. MPA방식은 검색엔진에 노출되기 쉽고, 첫 로딩이 짧아 많이 사용되었던 방식이다.
그러나, MPA 방식은 새로운 페이지를 요청할 때마다(ex) 로그인, 장바구니...) 서버에 HTML문서를 요청하고, 그때마다 서버에서 렌더링하여(SSR, Server-side Rendering) 매우 비효율적이라고 할 수 있다. 그래서 나온 패러다임이 바로 SPA(Single Page Application)이다.
SPA 방식은 단일 페이지로 시작하는데, 이때 웹 앱에 필요한 모든 리소스를 한 번에 전달받는다. 그 후, 유저와의 상호작용에 의해 페이지 갱신이 이루어질 시, 갱신에 필요한 데이터를 JSON형식으로 전달받아 페이지를 렌더링한다. (Client-side Rendering, CSR)
그렇기 때문에 SPA 방식은 변경되는 부분만을 렌더링하기 때문에(이는 React Virtual DOM의 가장 큰 장점이다) 새로 고침이 없어 속도도 빠르고, 편의성/사용성이 우수하다.
그러나 단점이라 한다면, 초기에 필요한 리소스를 한번에 다운로드하기 때문에 로딩이 느리고, SEO(검색엔진 최적화)문제가 발생할 수 있다. 그러나 현대의 React, Angular같은 라이브러리, 프레임워크는 Server-side Rendering을 지원하는 검색엔진 최적화 기술이 존재한다.
📢왜 CSR방식이 SEO문제를 유발하는가?
- 검색엔진들은 보통 HTML문서 자체를 분석해서 검색 결과에 노출시킨다.
- But, CSR(Client-side Rendering) 방식의 HTML은 body내용이 대부분 텅텅 비어있고, 클라이언트에서 자바스크립트 파일을 통해 웹사이트를 그리기 때문에 검색엔진이 HTML을 분석하는데 어려움을 겪는다.
따라서 기본 React는 CSR방식을 채택하고 있는데, 여기서 리액트 앱을 SSR방식으로 바꿔주는 것이 바로 Next.js이다. (Next.js는 공부중이라 추후 정리함)
리액트 앱은 SPA 방식이므로, 단지 하나의 index.html 파일을 갖고 있을 뿐이며 사이트 내에서 다른 사이트로 이동할 때에는 index.html에 다른 컴포넌트 자바스크립트 파일을 넣어서 페이지를 변경한다. 이때 Router가 어떤 자바스크립트 파일을 쓸 것인지 라우팅하여 탐색해주는 역할을 한다.
React Router의 사용
npm install react-router-dom --save
yarn add react-router-dom
index.js
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
<BrowserRouter>
<App/>
</BrowserRouter>
);
BrowserRouter: BrowserRouter 태그는 HTML5의 히스토리 API(pushState, replaceState, popstate)를 이용하여 컴포넌트를 라우팅한다. 주로 동적인 페이지에 사용한다.
HashRouter: HashRouter 태그는 BrowserRouter 태그와 달리 URL 해쉬값을 이용하여 컴포넌트를 라우팅한다. 주로 정적인 페이지에 사용한다.
App.js
function App(){
return(
<div className="App">
<Routes>
<Route path="/" element={ <Home/> } />
<Route path="about" element={ <About/> } />
<Route path="contact" element={ <Contact/> } />
</Routes>
</div>
);
}
Routes: 앱에서 생성되는 모든 Route에 대한 컨테이너 역할을 하며, 맨 첫번째 Route 컴포넌트를 렌더링하는 역할을 한다.
Route: 단일 경로를 만드는데 사용
- path: 컴포넌트의 URL 경로를 지정
- element: 경로에 맞게 라우팅할 수 있도록 렌더링할 컴포넌트를 지정
Link
function Home(){
return(
<div className="App">
<Link to="about">About으로 ㄱㄱ</Link>
</div>
);
}
Link 태그는 기본적으로 a태그와 동일한 역할을 하며, Link 태그로 이동한 페이지는 URL만 바뀔 뿐 새로 페이지를 로드하지는 않는다. (path를 이용하여 페이지를 이동하는 방식)
중첩 라우팅과 Outlet
중첩 라우팅을 사용하면 레이아웃 코드를 Route 코드 내에서 서브 페이지를 만들어 줄 수 있다.
App.js
function App(){
return(
<div className="App">
<button>
<Link to="/"> HOME </Link>
</button>
<button>
<Link to="about"> ABOUT </Link>
</button>
<button>
<Link to="contact"> CONTACT </Link>
</button>
<Routes>
<Route path="/" element={ <Home/> } />
<Route path="about" element={ <About/> }>
<Route path="location" element={ <Location/> } />
</Route>
<Route path="contact" element={ <Contact/> } />
</Routes>
</div>
);
}
여기서 About 엘리먼트에 location을 중첩하여 Routing을 넣어주었다. 이때 정상적인 코드를 짰다면 about/location 으로 URL을 접속해도 아무런 변화가 없다.
그 이유는 부모 라우트 컴포넌트에서 자식 라우트 컴포넌트의 위치를 지정해주지 않았기 때문인데, 이 코드가 작동하려면 about 컴포넌트에서 location 컴포넌트의 위치를 지정해주어야 한다. 이때 사용하는 것이 바로 Outlet이다.
About.js
import { Outlet } from 'react-router-dom';
function About(){
return(
<div>
<h2>여기는 About 페이지</h2>
<Outlet/>
</div>
);
}
About 페이지에서 자식 라우팅 컴포넌트 location이 들어갈 자리를 Outlet으로 지정해주었고, 실행시 about페이지의 서브 페이지로 location이 들어가는 것을 볼 수 있다.
React DOM API
🎈 useNavigate
import { useNavigate } from "react-router-dom";
let navigate = useNavigate();
...
navigate("../success", {replace : true}