[JS] Day6 - Type Ahead

jiseong·2021년 8월 23일
0

T I Learned

목록 보기
40/291
post-custom-banner

Day6 - Type Ahead

🎯 기능 요구사항

  • 사용자가 입력한 영문자를 포함하고 있는 도시 또는 주의 인구수를 나타낸다.

+ 무한 스크롤을 구현한다.

🚀 배운 점

fetch

const request = async (nodeId = '') => {
    try{
        const blob = await fetch(`${endpoint}/${nodeId}`);

        if(!blob.ok){
            throw new Error("Not 2xx response");
        }

        return await blob.json();
    } catch(e) {
        throw new Error(e);
    }
}

(async () => {
    const response = await request();
    ...
})();

axios와 동일하게 파라미터로 요청을 보낼 url을 입력해 주고 응답을 받아서 추가적인 작업 또한 해줄 수 있으며 리턴 타입은 promise 객체이다.
그래서 async await로 처리해주었고 성공적인 응답이 아닐시에만 예외 처리를 했다.

replace()

const result = place.state.replace(regExp, `<span class="hl">${keyword}</span>`);

패턴에 일치하는 일부 또는 모든 부분이 교체된 새로운 문자열을 반환하는 메소드로 regExp 패턴에 부합하는 부분을 하이라이트 표현해주기 위해 사용되었다.

무한 스크롤

n이라는 영문자를 입력시 해당 되는 state나 city의 목록은 대략 800개 정도가 나온다. 이게 이미지였다면 페이지의 로딩 속도에 문제가 생길수도 있을것같다는 생각이 들었다. 그리고 어차피 나중에 구현해보고 싶었던 기능이였기 때문에 해당 미니 프로젝트에 적용을 해보았다.

const observer = (function(){

    let restList = undefined;

    function onObserver(rest) {
        restList = rest;
        let li = document.querySelector("li:last-child");
        const DATA_PER_PAGE = 10;
        console.log(restList)
    
        // IntersectionObserver 생성
        const io = new IntersectionObserver((entries, observer) => {

            entries.map(entry => {
                // 타겟이 교차영역에 보일 시
                if (entry.isIntersecting) {

                    // 타겟 감시 취소
                    observer.unobserve(li);
        
                    suggestions.innerHTML += restList.slice(0, DATA_PER_PAGE).join('')
                    restList.splice(0, DATA_PER_PAGE);

                    // 새로운 타겟 지정
                    if(restList.length !== 0){
                        li = document.querySelector("li:last-child");
                        observer.observe(li);
                    }
                }
            });
            }, {
                //options
                threshold: 0.5
        });
    
        // 타겟 지정
        if(restList.length !== 0) io.observe(li);
    }

    return {
        onObserver
    }
})();

내가 사용한 방식은 Window Scroll방식이 아닌 Intersection Observer API를 활용한 방식이다. Window Scroll방식을 사용하지 않는 이유는 scroll의 특정 지점을 관찰하기 위해서 리플로우(reflow)현상이 일어나고 단시간에 수많은 호출이 일어나기 때문에 퍼포먼스 측면에서 효율적이지 못하기 때문이다. 해당 내용은 참고 사이트를 참고하면 좋다.

처음 fetch를 사용하여 필요한 정보를 받아온 후 10개의 목록만 화면에 로드하였고 나머지 부분을 Intersection Observer API를 활용하여 마지막 요소가 threshold만큼 교차영역에 보인다면 나머지 10개를 계속 불러오는 방식으로 구현하였다.

리플로우 는 문서내의 요소들에 대해서 위치와 좌표를 다시 계산하는 웹 브라우저의 프로세스이다. 이는 문서의 일부분 혹은 전부를 다시 렌더링 할 때 사용된다.

Intersection Observer

우선, new IntersectionObserver()를 이용하여 인스턴스를 생성하고
이때, 생성자는 인수로 callback과 options를 가진다.

const io = new IntersectionObserver(callback, options); // 관찰자 생성

관찰할 타겟요소를 등록한다.

io.observe(element); // 관찰할 타겟요소 등록
callback

관찰할 타겟이 등록되거나 가시성에 변화가 생길 때 해당 관찰자 콜백을 실행한다.
이때, 콜백은 파라미터로 entries와 observer를 받는다.

const io = new IntersectionObserver((entries, observer) => {...}, options)
  • entries

    entries에는 다음과 같은 정보가 저장되어있다.

    • rootBounds: 지정한 루트 요소의 사각형 정보
    • intersectionRect: 타겟 요소의 교차한 영역 정보
    • boundingClientRect: 타겟 요소의 사각형 정보
    • intersectionRatio: 타겟 요소의 교차한 영역 비율
      (0.0과 1.0 사이의 숫자로 반환)
    • isIntersecting: 타겟 요소와 관찰자의 루트의 교차 상태
      (교차상태에 따라 true/ false로 반환)
    • target: 타겟 요소
      (타겟 요소를 반환)
    • time: 변경이 발생한 시간 정보
  • observer

    • 콜백을 호출한 IntersectionObserver를 참조한다.
options

관찰자를 조정할 수 있는 옵션 객체이다.

지정하지 않는다면 관찰자는 문서의 뷰포트를 root로 사용하고 rootMargin은 0px 0px 0px 0px이며 threshold는 0.0이다.

  • root
    타겟요소의 가시성을 감시하기 위해 뷰포트 대신 사용할 요소를 지정한다.
  • rootMargin
    지정된 root범위를 확장하거나 축소한다.
  • threshold
    타겟 요소와 root 영역에 대한 교차 영역의 비율을 지정한다.
Methods
disconnect()

IntersectionObserver가 관찰하고 있는 모든 타겟요소의 관찰을 중지한다.

observe()

관찰할 요소를 추가한다.

unobserve()

단일 타겟요소의 관찰을 중지한다.

demo:

https://danji-ya.github.io/JS_javascript30/06-TypeAhead/


Reference

post-custom-banner

0개의 댓글