Infinite Scroll

송승찬·2020년 10월 5일
0

TIL

목록 보기
43/52
post-custom-banner

알아야 할것

  1. Intersection Observer API
  2. react hooks (useState,useEffect,useRef)

Intersection Observer API

  • 스크롤 이벤트 발생시마다 eventListener를 발생시키는 것은 javascript의 main thread에 계속 성능상 영향을 줌,따라서 특정 요소가 내가 원하는 영역에 들어왔을 때만 이벤트 발생시키는 API가 필요->이걸 도와주는 게 InterSection Observer API

  • 즉 스크롤 이벤트 발생시,계속해서 스크롤 값을 측정할 필요없이 특정 요소가 언제 viewport를 진입하고 빠져나가는지를 관찰해주는 API

  • Intersection Observer가 등장하기 전에는 어떤 요소가 화면에 보여지는지 감지하는 것은 매우 복잡한 일. 따라서 요소의 visibility를 감지하고 이벤트를 주는 것은 웹 사이트들을 느리게 만드는 원인 중 하나였고 따라서, Intersection 정보들이 필요하게 되었다.

  • 우리는 언제 유저가 특정 요소에 진입하는지 확인하고 이에 따라서 포스트를(DOM) 더 불러올지 결정하는 데 사용할 것

참고 : https://developer.mozilla.org/ko/docs/Web/API/Intersection_Observer_API

React InfiniteScroll

  • 폴더 구성

    npx create-react-app infiniteScroll

  1. useRef,useEffect를 가져와서 <div className='loading>Loading</div>에 붙임
  2. 컴포넌트 마운트 완료시 Intersection Observer를 <div className='loading>Loading</div>에 등록
  3. 우리가 어느 페이지에 있는지 확인하고 관찰하기 위해 state에 page추가
  4. 스크롤시 page업데이트하고 새로운 포스트를 불러오기

App.js

import React from 'react';
import InfiniteScroll from './InfiniteScroll';

function App() {
  return (
    <div className="App">
      <h2 style={{textAlign:'center'}}>InfiniteScroll Practice</h2>
      <InfiniteScroll />
    </div>
  );
}

export default App;

InfiniteScroll.js

import React,{useState,useEffect,useRef} from 'react'


const postStyle = {
    color: 'blue',
    height: '200px',
    textAlign: 'center',
    padding: '5px 10px',
    background: 'pink',
    marginTop: '15px',
    display:'flex',
    justifyContent:'center',
    alignItems:'center'
  };
  
  const containerStyle = {
    maxWidth: '760px',
    margin: '0 auto'
  }


function InfiniteScroll() {
    const [postList,setPostList] = useState({
        list :[1,2,3,4]
    })
    //tracking on Which page we currently are
    const [page,setPage] = useState(1);
    //referencing loader
    const loader = useRef(null);

    useEffect(()=>{
        const option = {
            root : null,
            rootMargin : '20px',
            threshold:0
        }
        //컴포넌트 렌더링 완료시,initialize IntersectionObserver and attaching to Load More div
        const observer = new IntersectionObserver(handleObserver,option);
        if (loader.current) {
            observer.observe(loader.current)
        }
    },[]);
    useEffect(()=>{
        //현재 page변할 때마다 실행하는 useEffect
        let addList = ['a','b','c','d'];
        const newList = setPostList({list : [...postList.list,...addList]});
    },[page])

    // 유저의 스크롤이 Load More div에 intersection(진입시) 무엇이 일어날지 다룸
    // 즉, 페이지 변수를 업데이트
    const handleObserver = (targetList)=>{
        const target = targetList[0];
        if (target.isIntersecting) {
            setPage(page=>page+1);
        }
    }

    const renderCard = postList.list.map((post,index)=>(
        <div key={index} className='post' style={postStyle}>
            <h2>{post}</h2>
        </div>
    ))
    return (
        <div className='container' style={containerStyle}>
            <div className='post-list'>
                {renderCard}
                <div className='loading' ref={loader}>
                    <h2>Load More</h2>
                </div>
            </div>
        </div>
    )
}


export default InfiniteScroll

결과

동작영상:

https://github.com/superfly9/react-infinite-scroll

사진:

참고: https://dev.to/hunterjsbit/react-infinite-scroll-in-few-lines-588f

profile
superfly
post-custom-banner

0개의 댓글