無限スクロール



無限スクロール


無限スクロールとは?これは、ユーザーが必要なページ番号を入力してページの下部にスクロールできるようにするページ処理方法で、ページの下部にスクロールするたびに次のページを順番にロードする必要はありません.
無限スクロールを実現するには、まずページの下部にスクロールされていることを認識する必要があります.この点を理解するには、スクロールするたびにイベントが発生し、スクロール位置が検出されることを確認する必要があります.ただし、JavaScriptのスクロールイベントは少し移動するだけで発生するため、何の制限もなくイベントを一時停止すると大量のイベントが発生し、リソースが浪費されます.従って、従来、スクロールイベントを実施する際にDeboringおよびThrottleが用いられている.

Debounce?


繰り返し実行されるイベントを組み合わせて、実行を制御する方法の1つです.特定の時間を設定し、その時間内にイベントを実行すると、以前に実行したすべてのイベントがキャンセルされ、時間が初期化されます.つまり、前回実行したイベントが設定時間内にリフレッシュされない場合、イベントは非状態で実行されます.

Throttle?


同様に、同じイベントの繰り返し実行を制御する方法.同様に、必要な時間を設定し、その時間を基準にイベントを制御します.設定時間内に発生した同じイベントは、設定時間の終了時に1回のみ実行されます.バスは一定時間ごとに駅に来ていますが、同じ客が1人しか乗れないのは理解できます.
上記2つのイベント制御方法は、いずれも、過度に繰り返し実行されるイベントのリソース浪費を防止するために提案されている.これは悪いイベント制御方式だとは思いませんが、無限スクロールを実施する上では、少し不足しているように見えます.
Deboringが無限スクロールに適用される場合、ユーザーが最後のページをスクロールしてからしばらくの間、次のページをスクロールする必要がないため、適切ではありません.Throttleはユーザーが認識しにくい時間設定に設定されているので、不快感を感じませんが、最後のページをスクロールする前に何回か点灯する可能性があります.必要なイベントが発生したため、できるだけより良い方法でイベントを制御することを望んでいます.JavaScriptが提供するInterSection Observer APIが見つかりました.

InterSection Observer API?


ブラウザビューポートと被観測要素の交差点を観察し、要素がビューポートに含まれているかどうか、ユーザー画面に含まれているかどうかを区別する機能を提供します.それを利用して多様な活動を実現することができます.
InterSection Observerを使用して無限スクロールを実行するのは、DeboringまたはThrottleとは異なり、プライマリ・スレッドに影響を与えることなく非同期で実行されます.観測された瞬間にイベントが発生するため,より効果的にイベントを制御することができる.そこで,InterSection Observerを用いて無限スクロールを実現した.
InterSection Observerは、無限スクロールに必要なisIntersctingを使用したさまざまな機能を提供しています.isIntersctingは、ビューポートにターゲットが表示されているかどうかを判断するInterSection ObserverのAntreeです.
isIntersctingを使用して無限スクロールを実現するのは簡単です.まず、ページの一番下に観測オブジェクトを作成します.次に、ターゲットが画面に表示されると、サーバ側にapiを要求して次のページをロードします.
const InfinityScroll = ({ page }) => {
  const dispatch = useDispatch();
  const searchSetting = useSelector((state) => state.post.searchSetting);
  const getMoreTrigger = React.useRef();

  const getMoreObserver = new IntersectionObserver((entry) => {
    if (entry[0].isIntersecting) {
      const newSearchSetting = { ...searchSetting, page: page + 1 };
      dispatch(postActions.setSearch(newSearchSetting));
      dispatch(postActions.getMorePostMW(newSearchSetting));
    }
  });

  React.useEffect(() => {
    getMoreObserver.observe(getMoreTrigger.current);

    return () => getMoreObserver.disconnect();
  }, []);
  return <div ref={getMoreTrigger} />;
};
ただし,リフレッシュなどの行為によりページの内容が瞬時に消失し,観測されると一度に複数のページが読み込まれる可能性があることに注意が必要である.これを防ぐには、値をロードしているかどうかを決定し、値を保存し、値がtrueでない場合(ロードされていない場合)にのみ無限スクロールを開始する値を作成します.これにより、望ましくない場合の無限スクロールの発生を制御できます.
const getPostMW = (searchData) => {
  return function (dispatch, getState) {
    dispatch(setLoading(true));
    apis
      .getPots(searchData)
      .then((res) => {
        if (res.data.data.postList.length === 0) {
          ErrorAlert('해당 조건 맞는 친구들이 없습니다!');
          dispatch(setSearchPrev());
          dispatch(setLoading(false));
          return;
        }
        dispatch(getPost(res.data.data.postList));
        dispatch(setTotalPage(res.data.data.totalPages));
        dispatch(setLoading(false));
      })
      .catch((err) => {
        console.log(err);
      });
  };
};// 처음 포스트를 불러오는 미들웨어

const getMorePostMW = (searchData) => {
  return (dispatch) => {
    dispatch(setLoading(true));
    apis
      .getPots(searchData)
      .then((res) => {
        dispatch(getMorePost(res.data.data.postList));
        dispatch(setTotalPage(res.data.data.totalPages));
        dispatch(setLoading(false));
      })
      .catch((err) => {
        console.log(err);
      });
  };
}; // 포스트를 더 불러오는 미들웨어

{isLoading || totalPage <= searchSetting.page || totalPage === 1 ? (
        ''
      ) : (
        <InfinityScroll page={searchSetting.page} />
      )} // 로딩 중이거나 더 이상 불러올 페이지가 없으면 무한스크롤 컴포넌트를 화면에서 없앴다