김민태 - JavaScript & TypeScript Essential (1)

Seuling·2022년 6월 23일
0

FE

목록 보기
27/42
post-thumbnail

변하지 않는 기술
네트워크, 운영체제, 컴퓨터시스템, 논리학, 대수학

느리게 변하는 기술
프로그래밍 언어, 프로그래밍 패러다임, 자료구조, 보안, 알고리즘

빠르게 변하는 기술
프레임워크, 라이브러리, UI, UX, 디자인패턴

4가지 프로그래밍 역량
일관성, 유연성, 확장성, 독립성

Javascript Starter Kit_Hacker News Client

제약사항

  1. 서버 없음 -> 해커뉴스 API

    https://hnpwa.com/
    https://github.com/tastejs/hacker-news-pwas

  2. 디자인 -> tailwindcss

  3. 비동기 메커니즘 -> 필수적 매커니즘이지만, hacker 프로젝트에서만 제외!

일단 해보기

  • ajax : 네트워크 너머에 있는 데이터를 가져오는 도구
  • XMLHttpRequest
    - XMLHttpRequest (XHR) 객체는 서버와 상호작용할 때 사용한다.
    - XHR을 사용하면 페이지의 새로고침 없이도 URL에서 데이터를 가져올 수 있다.
    - 이를 활용하면 사용자의 작업을 방해하지 않고 페이지의 일부를 업데이트할 수 있다.
const ajax = new XMLHttpRequest();

ajax.open("GET","https://api.hnpwa.com/v0/news/1.json", false);

ajax.send();
console.log(ajax.response);

🚨 parcel이 바로 안되어 그냥 Liveserver로 하였더니... CORS문제....

일단, parcel 을 설치해보자!

💚 해결!

Network탭 에서 -> news?page=2 -> Response 콘솔에 찍혔던 받아온 그대로의 데이터

Network탭 에서 -> news?page=2 -> Preveiw 자바스크립트로 다루기 쉬운 방식으로 바뀌어진 형식으로 미리보여주는 탭

이와같이 코드로 짠다면 ?

const newsFeed = JSON.parse(ajax.response);
console.log(newsFeed);

const newsFeed = JSON.parse(ajax.response);
const ul = document.createElement("ul");

for (let i = 0; i < 11; i++) {
  const li = document.createElement("li");
  li.innerHTML = newsFeed[i].title;
  ul.appendChild(li);
}

document.getElementById("root").appendChild(ul);

현재까지의 화면

두개의 화면을 가진 웹앱(라우팅)

window.addEventListener("hashchange", function () {
  console.log("해시가 변경됨");
});


window.addEventListener("hashchange", function () {
  const id = this.location.hash.substr(1);
  ajax.open("GET", CONTENT_URL.replace("@id", id), false);
  ajax.send();

  const newsContent = JSON.parse(ajax.response);
  console.log(newsContent);
});

이제, 콘텐츠를 불러왔으니까 화면에 어떻게 표현할 것인가를 결정해야지!
1. 콘텐츠를 표현할 영역을 만들고 + 2. 그 영역에 타이틀만 얹히는 형태

const content = document.createElement("div");

window.addEventListener("hashchange", function () {
  const id = this.location.hash.substr(1);
  ajax.open("GET", CONTENT_URL.replace("@id", id), false);
  ajax.send();

  const newsContent = JSON.parse(ajax.response);
  const title = this.document.createElement("h1");

  title.innerHTML = newsContent.title;
  content.appendChild(title);
});


document.getElementById("root").appendChild(ul);

  • innerHTML을 통한 코드 리팩토링

for (let i = 0; i < 11; i++) {
  const div = document.createElement("div");
  const li = document.createElement("li");
  const a = document.createElement("a");

  div.innerHTML = `
  <li>
    <a href='#${newsFeed[i].id}'> ${newsFeed[i].title}(${newsFeed[i].comments_count})</a>
  </li>
  `;

  ul.appendChild(div.firstElementChild);
}

container.appendChild(ul);
container.appendChild(content);
  • ajax호출 부분이 반복되니 묶어서 함수로 만들어야겠다! 리팩토링

    함수를 만들고 그 함수가 할 일의 코드를 묶어 주고 그 코드가 동작되기 위한 입력 값을 정의해서 사용해 주고 그리고 함수의 처리 결과를 return으로 반환해 주고!

ajax.open("GET", NEWS_URL, false);
ajax.send();
const newsFeed = JSON.parse(ajax.response);

//리팩토링

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

  return JSON.parse(ajax.response);
}

const newsFeed = getData(NEWS_URL);

const newsContent = getData(CONTENT_URL.replace("@id", id));

라우터

  • 글목록화면의 함수를 함수로 묶어주는 것 실행

//글 목록화면
const newsList = [];
newsList.push("<ul>");
for (let i = 0; i < 10; i++) {
  newsList.push(`
    <li>
      <a href="#${newsFeed[i].id}">
    
        ${newsFeed[i].title}(${newsFeed[i].comments_count})
      </a>
    </li>`);
}
newsList.push("</ul>");
container.innerHTML = newsList.join("");
//리팩토링

function newsFeed() {
    //글 목록화면
  const newsFeed = getData(NEWS_URL);
  const newsList = [];
  newsList.push("<ul>");
  for (let i = 0; i < 10; i++) {
    newsList.push(`
    <li>
      <a href="#${newsFeed[i].id}">
    
        ${newsFeed[i].title}(${newsFeed[i].comments_count})
      </a>
    </li>`);
  }
  newsList.push("</ul>");
  container.innerHTML = newsList.join("");
}

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

  if (routePath === '') {
    newsFeed();
  } else {
    newsDetail();
  }
}


window.addEventListener('hashchange', router);

router();

페이징

  • 현재 페이지가 몇번째 페이지인지 알고 있어야함
  • 그 페이지의 특성은? 변화하겠지~! 1페이지 보고있을 때 2페이지 보고있을 때의 상태
  • 즉, 현재페이지가 몇번째 페이지인지를 기억하는 변수 let 이 필요함
  • 페이지의 정보는 어디에서 사용되지? 글목록, 글내용 함수에서도 몇 번째 페이지로 돌아갈 거야 라고 말하는..!
  • 함수 바깥에다 해야겠군
const store = {
  currentPage: 1,
};

//글 목록화면
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 > store.currentPage - 1
        ? store.currentPage + 1
        : store.currentPage
    }'>다음 페이지</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();


템플릿 렌더링

//글 목록화면

function newsFeed() {
  const newsFeed = getData(NEWS_URL);
  const newsList = [];
  let template = `
    <div class="container mx-auto p-4">
      <h1>Hacker News</h1>
      <ul>
        {{__news_feed__}}      
      </ul>
      <div>
        <a href="#/page/{{__prev_page__}}">이전 페이지</a>
        <a href="#/page/{{__next_page__}}">다음 페이지</a>
      </div>
    </div>
  `;

  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>
    `);
  }

  template = template.replace('{{__news_feed__}}', newsList.join(''));
  template = template.replace('{{__prev_page__}}', store.currentPage > 1 ? store.currentPage - 1 : 1);
  template = template.replace('{{__next_page__}}', store.currentPage + 1);
  
  container.innerHTML = template;
}
profile
프론트엔드 개발자 항상 뭘 하고있는 슬링

0개의 댓글