리액트 애플리케이션의 페이지 전환은 단일 페이지 애플리케이션(Single Page Application, SPA) 방식으로 개발하는 것이 정석입니다.
단일 페이지 애플리케이션은 초기 요청 시 서버에서 첫 페이지를 처리하고 이후의 라우팅은 클라이언트에서
처리하는 웹 애플리케이션 입니다.
전통적인 방식의 웹 페이지는 페이지를 전환할 때마다 랜더링 결과를 서버에서 받기 때문에 화면이 깜빡이는 단점이 있습니다.
단일 페이지 애플리케이션은 페이지 전환에 의한 랜더링을 클라이언트에서 처리하기 때문에 마치 네이티브 애플리케이션 처럼 자연스럽게 동작합니다.
브라우저 히스토리 API
먼저 단일 페이지 애플리케이션을 구현하기 위해 필요한 브라우저 히스토리 API가 있습니다.
히스토리 API란?
단일 페이지 애플리케이션 구현이 가능하려면 다음 두가지 기능이 필요합니다.
- JS에서 브라우저 페이지 전환 요청을 보낼 수 있습니다. 단! 브라우저는 서버로 요청을 보내지 않아야 합니다.
- 브라우저의 뒤로가기와 같은 사용자 페이지 전환 요청을 JS에서 처리할 수 있습니다. 이때도 브라우저는 서버로 요청을 보내지 않아야 합니다.
이러한 조건을 만족하는 브라우저 API는
pushState , reaplaceState , popState
이런 이벤트가 있습니다.
API이름에서 알 수 있듯이 브라우저에는 히스토리에 State 를 저장하는 스택이 저장합니다.
브라우저 히스토리 API의 사용법을 확인해 보기 위해 App.js 파일을 다음과 같이 수정해 보겠습니다!!
실습을 위해서 bookreactjs에 폴더(저의 최상의 폴더)에서
npx create-react-app router-app 으로 새로 생성해 보겠습니다.
생성했으니 App.js 파일을 수정해보겠습니다.
import React, {useEffect} from 'react';
import './App.css';
export default function App() {
useEffect(()=>{
window.onpopstate = function(event){
console.log(`location : ${document.location}, state : ${event.state}`);
};
}, []);
return (
<div className="App">
<button onClick={()=> window.history.pushState('v1','','/page1')}>page1</button>
<button onClick={()=> window.history.pushState('v2','','/page2')}>page2</button>
</div>
);
};
위와같은 버튼 2개가 나타나는것을 확인하고
구글홈페이지로 이동 -> localhost:3000 입력해서 이동 -> 버튼1번, 2번 번갈아 눌러보기
를 해보겠습니다.
Url이 /page1, /page2 로 번갈아 변경되는 것을 확인 할 수 있습니다.
이때 서버로 요청이 가지 않고 화면도 변하지 않습니다.
단지 stack 에 state가 쌓일 뿐입니다.
코드 중에 onpopstate 함수도 호출되지 않습니다.
iseEffect함수는 이벤트 핸들러를 등록하거나 API를 호출하는 등의 부수 효과를 처리할 때 사용하는 훅입니다.
여기서는 컴포넌트가 마운트된 후에 popstate 이벤트 핸들러를 등록하는 용도로 사용했습니다.
이번에는 브라우저의 뒤로가기 버튼을 눌러 보겠습니다.
개발자모드로 보면 onpoptste 함수가 호출되는 것을 확인할 수 있습니다.
계속해서 뒤로가기를 누르면 스택이 비워질 때까지 onpopstate 함수가 호출되다가 최초에 접속했던 구글 홈페이지로 들어가게 됩니다.
처음에 언급했던 두 가지 기능이 pushState 함수와 popstate 이벤트로 모두 구현 되었습니다.
replacestate 함수는 pushState 와 거의 같지만 스택에 state 를 쌓지 않고 가장 최신의 state 를 대체합니다.
이렇게 pushState , replaceState 함수와 popstate 이벤트만 있으면 클라이언트에서 라우팅 처리가 되는 단일 페이지 애플리케이션을 만들 수 있게됩니다.
브라우저 히스토리 API를 이용해서 간단한 단일 페이지 애플리케이션을 만들어 보겠습니다.
App.js 파일에 다음 코드를 입력해 보겠습니다.
import React, {useEffect, useState} from 'react';
export default function App() {
const [pageName, setPageName] = useState('');
useEffect(() => {
window.onpopstate = event => {
setPageName(event.state);
};
}, []);
function onClick1() {
const pageName = 'page1';
window.history.pushState(pageName, '', '/page1');
setPageName(pageName);
}
function onClick2() {
const pageName = 'page2';
window.history.pushState(pageName, '', '/page2');
setPageName(pageName);
}
return (
<div>
<button onClick={onClick1}>page1</button>
<button onClick={onClick2}>page2</button>
{!pageName && <Home/>}
{pageName === 'page1' && <Page1/>}
{pageName === 'page2' && <Page2/>}
</div>
);
}
function Home() {return <h2>Please click button.</h2>;}
function Page1() {return <h2>This is page 1.</h2>;}
function Page2() {return <h2>This is page 2.</h2>;}
- 현재 페이지 정보를 pageName 상탯값으로 관리합니다.
- popstate 이벤트가 발생하면 페이지를 전환한다는 의미로 pageName 상탯값을 수정합니다. 브라우저 히스토리 state를 페이지 이름으로 사용하고 있습니다.
- 페이지 버튼을 클릭했을 떄 호출되는 이벤트 처리함수들을 넣어주었습니다.
- 페이지 버튼을 누르기 전에는 Home컴포넌트가 랜더링 되게됩니다.
- 첫번째 페이지 버튼을 클릭하면 page1 컴포넌트가 랜더링 되고, 두 번째 페이지 버튼을 클릭하면 page2 컴포넌트가 랜더링됩니다.
페이지 버튼을 클릭하면 브라우저 주소창의 내용이 변경되고, 브라우저의 뒤로가기 버튼을 클릭해도 의도한 대로 잘 동작하는 것을 확인할 수 있습니다.
React-router-dom 사용하기
react-router-dom 은 리액트 단일 페이지 애플리케이션을 만들 때 많이 사용됩니다. 이를 위해 해당 패키지를
지금 실습중인 폴더에 설치를 해보겠습니다.
npm install react-router-dom
지금까지 App,js 파일을 수정해보겠습니다.
import React from 'react';
import {ReowserRouter, Route, Link, BrowserRouter} from 'react-router-dom';
import Rooms from './Rooms';
export default function App() {
return (
<BrowserRouter>
<div style ={{ padding :20, border : '5px solid gray'}}>
<Link to="/">Home</Link>
<br />
<Link to ="/phote">Picture</Link>
<br />
<Link to="rooms">Introduction of Room</Link>
<br />
<Route exact path ="/" component={Home}/>
<Route path="/photo" component={Phote}/>
<Route path="/rooms" component={Rooms}/>
</div>
</BrowserRouter>
);
}
function Home({match}){return <h2>This is Homepage</h2>;}
function Phote({match}){return <h2>picture</h2>;}
우선 App.js 를 작성했습니다.
- react-router-dom 을 사용하기 위해서 전체를 BrowserRouter 컴포넌트로 감싸야 합니다.
- 버튼을 통해서 페이지를 전환할 때는 react-router-dom 에서 제공하는 Link 컴포넌트를 이용했습니다. to 속성값은 이동할 주소를 나타냈습니다.
- react-router-dom 의 Route 컴포넌트를 이용해서 각 페이지를 정의합니다. 현재 주소가 path 속성값으로 시작하면 component 속성값이 가리키는 컴포넌트를 렌더링합니다. 예를들어 localhost:3000/photo/abc 를 입력했을 때 주소가 /photo 로 시작하므로 photo 컴포넌트가 랜더링 됩니다. 그러나 localhost:3000/phote123을 입력하면 photo 컴포넌트가 랜더링되지 않습니다. 이는 슬래시 단위로 비교를 하도록 했기 때문입니다.
- exact 속성값을 입력하면 그 값이 완전히 일치해야 해당 컴포넌트가 랜더링 됩니다.
만약 Home 컴포넌트 부분에서 exact 속성값을 입력하지 않았다면 Home 컴포넌트는 항상 랜더링됩니다.

<Route exact path ="/" component={Home}/>
<Route path="/photo" component={Phote}/>
해당 코드의 이부분이 그렇습니다.
다음은 /rooms 로 접속했을떄 보여줄 Room.js를 작성해보겠습니다.
import React from 'react';
import { Route, Link } from 'react-router-dom';
function Rooms({ match }) {
return (
<div>
<h2>Introduction Rooms.</h2>
<Link to={`${match.url}/blueRoom`}>Blue style room</Link>
<br />
<Link to={`${match.url}/greenRoom`}>Green style room</Link>
<br />
<Route path={`${match.url}/:roomId`} component={Room} />
<Route exact path={match.url} render={() => <h3>choose you want</h3>}/>
</div>
);
}
export default Rooms;
function Room({ match }) { return <h2>{`you choose the ${match.params.roomId}`}</h2>; }
이 중간에 오류가 발생합니다.
[React] react-router-dom 설치 후 Route 시 오류를 해결해보겠습니다 밑의 링크를 눌러주세여!!
2022.01.23 - [React] react-router-dom 설치 후 Route 시 오류 / 해결방법
- Room컴포넌트 내부에는 또다시 라우팅을 처리하는 코드가 들어있습니다 .
- Route 를 통해서 랜더링되는 컴포넌트는 match 라는 속성값을 사용할 수 있습니다.
- match url은 Router 컴포넌트의 path 속성값과 같습니다. 따라서 Rooms 컴포넌트의 match.url은 /rooms 과 같습니다.
- Route 컴포넌트의 path 속성값에서 클론을 사용하면 파라미터를 나타낼 수 있습니다.
- 추출된 파라미터는 match.params.{파라미터 이름} 형식으로 사용될 수 있습니다.
첫 페이지에서는 Home 컴포넌트만 랜더링 됩니다. 이 화면에서 picture를 누르면 밑의 글이 사진으로 바뀝니다.
Home을 누르면 This is Homepage라고 변합니다.
이후 방소개를 누르고 하단의 글들을 누르면 계속 랜더링이 됩니다.
url도 http://localhost:3000/rooms/greenRoom
http://localhost:3000/rooms/blueRoom
이렇게 변합니다.
새창을 누르고 http://localhost:3000/rooms/blueRoom 를 검색해서 들어간다면 바로
이런화면이 나타나는것을 볼 수 있습니다.
'리액트 공부' 카테고리의 다른 글
CSS 작성 방법 "결정"하기 (0) | 2022.01.22 |
---|---|
AUTOPREFIXER (0) | 2022.01.21 |
Create-react-app으로 시작하기 (0) | 2022.01.20 |
웹팩의 기본 개념 이해하기 (0) | 2022.01.19 |
바벨 사용해 보기 (0) | 2022.01.19 |
댓글