그냥 실험용으로 간단하게 만들어 보았다. trend, upcoming을 클릭하고 page를 클릭하면 url이 ?trend?page=1
로 바뀌게 했다.
만약 search term이 있으면 ?searching?query='searchTerm'?page=1
요런식으로 주소가 바뀐다. 그리고 데이터는 따로 가공해서 pushState로 넘겨주고 popstate 이벤트를 통해 뒤로, 앞으로 갈때마다 넘겨받는다.
<form>
<input type="text" />
<button type="submit">button</button>
</form>
<div class="wrap">
<div class="container">
<!-- end of row -->
<div class="row">
<div class="columns twelve">
<div class="programs">
<button class="trend">trend</button>
<button class="upcoming">upcoming</button>
</div>
</div>
</div>
<!-- end of row -->
<div class="row">
<div class="twelve columns">
<h4>Programs List</h4>
</div>
</div>
<!-- end of row -->
<!-- end of container -->
</div>
<!-- end of wrap -->
<footer id="pagination">
<ul>
<li class="active">1</li>
<li class="no">2</li>
<li class="no">3</li>
<li class="no">4</li>
</ul>
</footer>
const $buttons = document.querySelector('.programs');
const $pages = document.querySelector('#pagination');
const $form = document.querySelector('form');
const $input = document.querySelector('input');
let state = {
dbType: null,
currentPage: 1,
searchingTerm: null,
};
const routerDispatcher = ({ dbType, searchingTerm, currentPage }) => {
window.dispatchEvent(
new CustomEvent('router-change', {
detail: {
dbType,
searchingTerm,
currentPage,
},
})
);
};
const initRouter = () => {
window.addEventListener('router-change', event => {
const { dbType, searchingTerm, currentPage } = event.detail;
const pushData = {
dbType,
searchingTerm,
currentPage,
};
window.history.pushState(
pushData,
null,
`?${dbType}${searchingTerm ? `?query=${searchingTerm}` : ''}${
currentPage ? `?page=${currentPage}` : ''
}`
);
});
window.addEventListener('popstate', event => {
if (event.state) {
const { dbType, currentPage, searchingTerm } = event.state;
state = { dbType, currentPage, searchingTerm };
console.log(state);
console.log(dbType, currentPage, searchingTerm);
}
});
};
//App
initRouter();
$buttons.addEventListener('click', e => {
const { className } = e.target;
if (className === 'trend' || className === 'upcoming') {
state.dbType = className;
routerDispatcher({ dbType: state.dbType });
}
});
$pages.addEventListener('click', e => {
const { nodeName, textContent } = e.target;
if (nodeName === 'LI') {
if (state.dbType) {
state.currentPage = textContent;
const { dbType, currentPage, searchingTerm } = state;
if (dbType === 'searching') {
routerDispatcher({ dbType, currentPage, searchingTerm });
} else {
routerDispatcher({ dbType, currentPage });
}
}
}
});
$form.addEventListener('submit', e => {
e.preventDefault();
state.dbType = 'searching';
state.searchingTerm = $input.value;
state.currentPage = 1;
const { dbType, currentPage, searchingTerm } = state;
routerDispatcher({ dbType, currentPage, searchingTerm });
$input.value = '';
});
우선 state객체를 만들어 안에 history에 들어갈 data를 정리한다.
그리고, initRouter로 커스텀 이벤트를 받아들일 준비를 한다. 또한, popstate까지 같이 세팅을 해주어 라우팅 준비를 완료한다.
이제 라우팅이 필요한 곳에 state를 업데이트 하고 , routerDispatcher를 불러들여 업데이트 된 state안에서 데이터를 필요에 따라 꺼낸 다음 선별적으로 pass한다.
그리고 popstate될때도 state까지 자동 업데이트 되도록 코드를 짜보았다.
사실, history와 popstate 이벤트 만으로도 라우팅을 구현할 수 있지만, 커스텀 이벤트를 사용해보고 싶어서 일단 적용해보았다.
이로써 SPA의 원리를 배웠다. 그리고 클라이언트에서 랜더링하는 CSR을 배웠다. 그럼 CSR과 서버단에서 랜더링하는 SSR의 차이점이 뭔지 다음글에서 알아보자.