MPA란 페이지가 여러개 존재하는 기존의 애플리케이션입니다.
1. MPA에서는 클라이언트가 초기 요청을 보내면, 서버는 html을 내려줍니다.
2. 이후에 페이지 전환 요청이 있으면 다시 서버로 요청을 보내고, 서버는 다시 html을 내려줍니다.
3. 그리고 클라이언트에서는 페이지를 다시 로딩합니다.
이러한 과정을 계속 반복하게 됩니다.
하지만 SPA 에서는 서버가 html을 내려주는 요청이 초기에 한번 뿐입니다.
1. SPA에서는 클라이언트가 초기 요청을 보내면 MPA와 마찬가지로 서버는 html을 내려줍니다.
2. 하지만 이후에 페이지 전환 요청이 있으면 서버로 항상 요청하는것이 아니라, 필요할 때만 데이터를 요청해서 받아옵니다.
3. 데이터만 받아와서 페이지를 자체적으로 라우팅 하기 때문에 html을 받을 필요 없습니다.
1. 자바스크립트에서 브라우저로 페이지 전환 요청을 보낼 수 있어야 합니다.
2. 브라우저의 뒤로가기와 같은 사용자의 페이지 전환요청을 자바스크립트에서 처리할 수 있어야합니다.
단, 위의 두가지 경우에 브라우저는 서버로 요청을 보내지 않아야합니다. 이러한 조건을 만족시키기 위해서 사용하는 브라우저 API가 있습니다.
pushState(함수), replaceState(함수), popstate(이벤트)
onpopstate 이벤트를 통해서 주소가 변경될 시에 url과 state 데이터를 출력하도록 정의했습니다.
pushState 함수에 state 데이터와 URL 데이터를 넣어서 해당하는 URL로 이동하도록 함과 동시에 데이터를 전달하였습니다.
onpopstate 함수에서 event.state 객체는 pushState 함수의 1번째 매개변수가 됩니다.
onpopstate 함수에서 document.location 객체는 기본 주소에 pushState 함수의 3번째 매개변수가 붙은 값이 됩니다.
window.onpopstate (event) |
window.history.pushState ($1, $2, $3) |
|
console.log(event.state) | $1 | $1 |
console.log(document.location) | http://localhost:XXXX/$3 | $3 |
function App() {
useEffect(() => {
window.onpopstate = function(event) {
console.log(`location: ${document.location}, state: ${event.state}`);
}
}, []);
return (
<div>
<button onClick={() => window.history.pushState('Hello', '타이틀', '/hello')}>
/hello 주소로 이동
</button>
</div>
)
}
조금 더 나아가서, 현재 페이지의 주소를 관리해주는 코드를 추가해보겠습니다.
이 코드를 추가하는 이유는, 현재 페이지의 주소에 따라서 다른 화면을 보여주기 위해서 입니다. 지금은 버튼을 클릭해도 주소만 바뀌고 화면이 바뀌지 않습니다. 따라서 아래와 같은 코드가 필요합니다!
pageName 이라는 변수에 값을 넣어주는 함수의 이름을 setPageName 으로 지정해주는 코드입니다.
var pageName;
function setPageName (value) {
pageName = value;
}
위와 같은 코드를 리액트에서는 아래와 같이 사용할 수 있습니다.
리액트 컴포넌트의 state 변수 안에 pageName을 정의한 다음, pageName에 값을 넣어주는 함수를 setPageName 이라는 이름으로 생성해줍니다.
const [pageName, setPageName] = useState('');
위의 코드를 적용해서 다시 App 컴포넌트를 작성해 보겟습니다.
function App() {
const [pageName, setPageName] = useState('');
useEffect(() => {
window.onpopstate = function(event) {
console.log(`location: ${document.location}, state: ${event.state}`);
}
}, []);
function onClickEvent() {
const pageName = 'home';
window.history.pushState(pageName, '', '/home');
setePageName(pageName);
}
return (
<div>
<button onClick={onClickEvent}>Home으로 이동</button>
{pageName === 'home' && <Home />}
</div>
)
}
라우팅을 도와주는 패키지를 사용하지 않고 코드가 분할되지 않은 상태로 작성을 한다면 한번에 대용량의 자바스크립트가 내려오게 됩니다. 따라서 사용자는 초기 페이지 로딩시에 느린 속도를 체험하게 됩니다. 지금 사용하려는 React Router DOM 패키지는 이러한 코드의 분할을 도와주는 패키지입니다.
React Router DOM 적용 전과 후에 어떻게 달라지는지 확인해보겠습니다.
function App() {
return (
<BrowserRouter>
<div>
<Link to="/home">홈</Link>
<Link to="/about">소개</Link>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
</div>
</BrowserRouter>
);
}
function Home() {
return <h2>홈</h2>;
}
function About() {
return <h2>소개</h2>;
}
위와 같이 Link 라는 컴포넌트에는 pushState 함수의 3번째 인자인 URL을 넣어주고 Route 컴포넌트에는 Link에 따라서 어떤 컴포넌트를 보여줄지 component 속성에 넣어줍니다.
따라서 React Router DOM을 사용하면, 링크의 이동은 Link 컴포넌트로, 주소에 따른 렌더링 화면은 Route 컴포넌트로 분할하여 코드를 작성할 수 있습니다.
단, Route 컴포넌트를 사용할 때 path의 값이 "/" 인 경우, 다른 컴포넌트와 같이 렌더링 될 수 있기 때문에 꼭 exact 속성을 정의해 주셔야 합니다.
출처 : 실전 리액트 프로그리맹 - 인프런 (추천합니다 !!)
[Frontend/React] 9. Fragment / Potal 사용하기 (0) | 2020.10.03 |
---|---|
[Frontend/React] 8. 컴포넌트의 속성값과 상태값 (0) | 2020.10.03 |
[Frontend/React] 6. SCSS 개발환경 구성하기 (0) | 2020.10.03 |
[강의/실전 리액트 프로그래밍] 5. 환경변수 (0) | 2020.10.03 |
[강의/실전 리액트 프로그래밍] 4. 지원되지 않는 JavaScript 함수처리 (0) | 2020.10.03 |