페이징 구현하기

dev__bokyoung·2022년 9월 2일
0

해커뉴스 클론코딩

목록 보기
4/12
post-thumbnail

프롤로그

지난 포스팅까지 두개의 화면을 만들었다.데이터를 불러오게 되면 많은 게시글이 있어 페이지네이션이 생기게 되는데 이번에는 페이징을 구현하고자 한다.

1. 페이징 구현하기

게시글 상세에서 목록보기를 클릭할 때 전에 보고 있던 페이지가 예를들어 2페이지라면 그대로 2페이지로 목록을 보여줘야 사용자가 원할하게 사용 할 것이다. (만약 1페이로 초기화가 된다면 좀 화날지도 😡 ) 그래서 그 페이지를 담는 변수가 필요한 데 여러 군데에서 사용되는 변수는 따로 객체를 만들어 담아 놓는 것이 좋다. (공유되는 자원들은 하나로 묶어놓자)

// 공유되는 자원이란 의미로 store 라고 명명 
const store = {
  currentPage: 1,
};

function newsFeed() {
  const newsFeed = getData(NEWS_URL);
  const newsList = [];

  newsList.push('<ul>');
  
  // 10개씩 게시글이 보여진다고 할 때 리스트가 10개씩 한 묶음으로 만들어 져야 하니까 10을 곱해주었다.
  for(let i = (store.currentPage - 1) * 10; i < store.currentPage * 10; i++) {
    newsList.push(`
        <li>
        <a href="#/show/${newsFeed[i].id}">
          ${newsFeed[i].title} (${newsFeed[i].comments_count})
        </a>
      </li>
    `);
  }
  
  newsList.push('</ul>');
  newsList.push(`
  <div>
    <a href="#/page/${store.currentPage - 1}">이전 페이지</a>
    <a href="#/page/${store.currentPage + 1}">다음 페이지</a>
  </div>
  `);
  
  container.innerHTML = newsList.join('');
}


주솟값이 #/page/currentPage , #/show/currentPage 이런식으로 바뀌었다. 그 이유인 즉슨 페이징을 구현하기 전에는 #뒤에 무조건 id 값이 온다고 생각해서 빈칸이면 목록을 구현하고 그렇지 않으면 상세를 보여주기로 했었다. 그런데 페이지네이션을 구현하게 되면 뒤에 무조건 뭔가가 올 테니까 구분할 인자가 필요 했다.

그래서 page 를 보여줄 항목에는 /page/
상세페이지는 /show/ 를 오게 처리해주고 주소 url 에 해당 단어가 들어 있으면 indexOf 목록 또는 상세페이지로 처리해 주었다.

function router() {
  const routePath = location.hash;

  if (routePath === '') {
    newsFeed();
  } else if (routePath.indexOf('#/page/') >= 0) {
    store.currentPage = Number(routePath.substr(7));
    newsFeed();
  } else {
    newsDetail()
  }
}

2. 결함 수정

이전에 작성 해 놓았던 코드를 살짝 수정 해보자


function newsDetail() {
//substr(1) 이 아니라 이제는 7이 되어야 한다. /page/ 등으로 구분을 해 놓았기 때문! 
  const id = location.hash.substr(7);
  const newsContent = getData(CONTENT_URL.replace('@id', id))

  container.innerHTML = `
    <h1>${newsContent.title}</h1>

    <div>
      <a href="#/page/${store.currentPage}">목록으로</a>
    </div>
  `;
}

3. 방어코드 작성

방어코드는 이런 것이다. 예를들면 이전 페이지를 눌렀을 때 currentPage -1 을 했는데 만약 현재페이지가 0 이었다면???
url 이 없는 페이지를 나타내게 하면 안되므로 조건문을 걸어서 처리 해 줘야 한다.

newsList.push(`
    <div>
      <a href="#/page/${store.currentPage > 1 ? store.currentPage - 1 : 1}">이전 페이지</a>
      <a href="#/page/${store.currentPage + 1}">다음 페이지</a>
    </div>
  `);

4. 전체 코드

const container = document.getElementById('root');
const ajax = new XMLHttpRequest();
const content = document.createElement('div');
const NEWS_URL = 'https://api.hnpwa.com/v0/news/1.json';
const CONTENT_URL = 'https://api.hnpwa.com/v0/item/@id.json';
const store = {
  currentPage: 1,
};

function getData(url) {
  ajax.open('GET', url, false);
  ajax.send();

  return JSON.parse(ajax.response);
}

function newsFeed() {
  const newsFeed = getData(NEWS_URL);
  const newsList = [];

  newsList.push('<ul>');
  
  for(let i = (store.currentPage - 1) * 10; i < store.currentPage * 10; i++) {
    newsList.push(`
      <li>
        <a href="#/show/${newsFeed[i].id}">
          ${newsFeed[i].title} (${newsFeed[i].comments_count})
        </a>
      </li>
    `);
  }
  
  newsList.push('</ul>');
  newsList.push(`
    <div>
      <a href="#/page/${store.currentPage > 1 ? store.currentPage - 1 : 1}">이전 페이지</a>
      <a href="#/page/${store.currentPage + 1}">다음 페이지</a>
    </div>
  `);

  container.innerHTML = newsList.join('');
}

function newsDetail() {
  const id = location.hash.substr(7);
  const newsContent = getData(CONTENT_URL.replace('@id', id))

  container.innerHTML = `
    <h1>${newsContent.title}</h1>

    <div>
      <a href="#/page/${store.currentPage}">목록으로</a>
    </div>
  `;
}

function router() {
  const routePath = location.hash;

  if (routePath === '') {
    newsFeed();
  } else if (routePath.indexOf('#/page/') >= 0) {
    store.currentPage = Number(routePath.substr(7));
    newsFeed();
  } else {
    newsDetail()
  }
}

window.addEventListener('hashchange', router);

router();

에필로그

이번에 배운 점은 공유되는 자원은 따로 빼 놓는 게 코드를 효율적으로 관리 하는 것 이다.

여담으로 .. 저 store 객체는 나중에 정~~ 말 어려워지는 코드로 변환하고야 마는데 ..ㅜㅜ 사실 store 부분에 이것저것 코드가 추가되고 하면서 따라가기 어려워서 처음으로 돌아오게 되었다. 이 부분은 정말 중요하다! !

profile
개발하며 얻은 인사이트들을 공유합니다.

0개의 댓글