[JS] 실습-NewsViewer

정세은·2022년 12월 3일

training

목록 보기
5/5

📌 News-viewer 구현

  • 무한 스크롤을 지원하는 news viewer 구현
  • Axios를 이용한 비동기 서버 통신
  • Observer API를 사용해 구현한 무한 스크롤
  • 전역 상태 관리 : Proxy를 통해 전역 상태가 변경되면 변경을 감지해 컴포넌트를 자동 리렌더링

위의 요소가 뷰포트와 교차하면 다음 뉴스를 취득해 기존 뉴스 뒤에 추가하는 방식으로 무한 스크롤 기능을 구현해 보려고 한다.
그래서 이번 실습에서는 옵저버 패턴프록시를 사용해서 전역 상태를 관리해 보았다.

❓Observer API란?

✔️ Intersection Observer API는 타겟 요소와 viewport 사이의 변화를 비동기적으로 관찰하는 방법이다.

Observer는 관측자, 혹은 감시자 라는 뜻을 가지고 있다. 말 그대로 무언가를 감시하는 역할을 한다는 것이다.
옵저버 패턴은 객체의 상태 변화를 관찰하는 관찰자들,
즉 옵저버들의 목록을 객체에 등록하여 상태 변화가 있을 때마다 메서드를 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 디자인 패턴이다.

아래는 내가 작성한 코드이다.

const observerElement = () => {
    const observerElement = document.createElement('div');
    observerElement.className = 'scroll-observer';
    observerElement.dataset.page = '1';

    const observerImg = document.createElement('img');
    observerImg.src = './img/ball-triangle.svg';
    observerImg.alt = 'Loading...';

    observerElement.appendChild(observerImg);

    return observerElement;
};

가장 먼저, 객체의 상태 변화를 관찰할 요소를 만들어 주었다.

const scrollObserver = (newsListArticle, scrollObserverElement) => {
    const callback = async (entries) => {
        for (const entry of entries) {
            if (entry.isIntersecting) {
                const nextPage = parseInt(entry.target.dataset['page']);
                const category = newsListArticle.dataset.category;

                const newsList = await getNewsList(nextPage, category);
                entry.target.dataset['page'] = nextPage + 1;

                if (newsList.length > 0) {
                    newsList.forEach((data) => {
                        newsListArticle.appendChild(data);
                    });
                    continue;
                }
                observer.unobserve(entry.target);
                entry.target.remove();
            }
        }
    };

    const observer = new IntersectionObserver(callback, {threshold: 1.0});
    observer.observe(scrollObserverElement);
};

뉴스를 가져오고 페이지 스크롤 시에 요소와 뷰포트가 교차하면, 다음 뉴스를 취득해서 기존 뉴스 뒤에 추가해주는 함수를 만들었다.

✔️ new 키워드를 통해 인스턴스를 생성한다.
        callback은 가시성의 변화가 생겼을 때 호출되는 콜백 로직을 작성해준다.

✔️ 타겟 요소를 작성해준다.

observer.observe(scrollObserverElement);

✔️ 타겟 요소의 관찰이 시작되고 변화가 감지되면, callback 함수가 실행된다.
       이 콜백은 파라미터로 entries와 observer를 받는다.
       entries : 인스턴스를 담은 배열
       isIntersecting : 해당 entry에 타겟 요소가 루트 요소와 교차하는 지 여부를 Boolean 값으로 반환한다.

✔️ 더이상 보여줄 뉴스 리스트가 없으면, 타겟 요소에 대한 관찰을 중지하고 타겟을 지워준다.

observer.unobserve(entry.target);
entry.target.remove();

❓Proxy란?

✔️ 프록시는 대상 객체 대신 사용된다.
대상 객체를 직접 사용하는 대신, 프록시 객체가 사용되며 각 작업을 대상 객체로 전달하고 결과를 다시 코드로 돌려준다.

이번 실습에서는 카테고리를 전역 상태로 관리하고자 한다.
전역 상태란, 모든 컴포넌트가 접근 가능한 상태를 말하며 전역 상태가 변경되면 상태에 의존하는 컴포넌트의 렌더링에 영향을 준다.

✔️ 프록시 객체 생성

new Proxy(target, handler)

프록시 객체를 생성하기 위해 new 키워드로 생성자를 호출하고 target과 handler 두 개의 인자를 필수로 받는다.
target: 처리를 해야 하는 대상 객체
handler: 작업이 수행될 때 프록시의 동작을 정의하는 속성이 함수인 객체

window.onload = async function() {
    const rootElement = document.getElementById('root');

    const proxyData = new Proxy({
        category: 'all',
    },
    {
        set: async function(target, prop, value) {
            Reflect.set(target, prop, value);
            const newsListElement = await NewsList(proxyData);
            const container = rootElement.querySelector('.news-list-container');

            if (container === null) {
                rootElement.appendChild(newsListElement);
            } else {
                container.replaceWith(newsListElement);
                return;
            }
        },
    });


    const navElement = Nav(proxyData);
    rootElement.appendChild(navElement);

    const newsListElement = await NewsList(proxyData);
    rootElement.appendChild(newsListElement);
};

이렇게 옵저버 패턴과 프록시를 통해서 전역 상태가 변경되면 변경을 감지해 전역 상태를 subscribe하고 있는 컴포넌트를 자동으로 리렌더링하는 뉴스 페이지를 구현해 보았다.

참고 : https://developer.mozilla.org/ko/docs/Web/API/Intersection_Observer_API
참고 : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Proxy

Github Repository 이동

0개의 댓글