React で無限スクロール コンポーネントを構築する

WBOY
リリース: 2024-08-26 21:45:02
オリジナル
1112 人が閲覧しました

導入

アプリケーションやウェブページ、特にソーシャルメディアではスクロールするだけで済む無限スクロールが見られます。何も考えずにスクロールするのは良くありませんが、独自の無限スクロールを構築するのは素晴らしいことです。開発者として、Web サーフィン中に目にするコンポーネントを再作成してみる必要があります。一部のコンポーネントを実装する際には、より多くのことを学び、既成概念にとらわれずに考えることが求められる場合があります。

また、アプリケーションに無限スクロールを実装したい場合は、ガイドに従って独自のスクロールを作成できます。独自のコードを追加して、スクロールの動作を改善できます。

この記事では、無限スクロール コンポーネントを最初から構築します。以下のトピックについて説明します:

  • 環境セットアップ
  • コンポーネントのビルド
  • CSS の追加
  • 無限スクロールの最適化

さて、始めましょう。

環境設定

CRA を使用して基本的な React アプリケーションを作成します。次のコマンドを実行することでこれを行うことができます:

    npx create-react-app infinite-scroll
ログイン後にコピー

Vite または NextJS を使用したい場合は、それも可能です。マイナーな変更を除けば、その他の点は変わりません。

注: このコマンドを実行するには、NodeJS が事前にインストールされている必要があります。 また、CRA から不要な定型コードの一部を削除します。

API からデータを取得するには、依存関係が 1 つ必要になります。 React を設定したら、次のコマンドで Axios をインストールできます:

    npm install axios
ログイン後にコピー

これで、コンポーネントを作成する準備が整いました。

アプリコンポーネント

Tmdb API から人気のある映画データを取得するコンポーネントを構築します。 API キーは Web サイトから無料で取得できます。まずデータを取得する場所を構築してから、無限スクロール機能を追加しましょう。

アプリ コンポーネントのコードは次のとおりです:

App.js

    import "./App.css";
    import { useState, useEffect } from "react";
    import axios from "axios";
    import { MovieCard } from "./MovieCard";

    function App() {
      const [page, setPage] = useState(1); // for number of page in tmdb 
      const [data, setData] = useState([]); // storing the fetched data
      const [loading, setLoading] = useState(false); // for setting loading state

      // fetching and stroring the data in the state
      const fetchMovie = async () => {
        const URL = `https://api.themoviedb.org/3/movie/popular?language=en-US&page=${page}`;
        const data = await axios.get(URL, {
          headers: {
            Authorization:
              "Bearer API KEY",
            Accept: "application/json",
          },
        });
        setData((prevData) => [...prevData, ...data.data.results]); // we are going to add the new data to current data.
        setLoading(false);
      };

      // useEffecte for invoking the function at the start
      useEffect(() => {
        fetchMovie();
      }, [page]);

      return (
        <div className="App">
          <header className="App-header">
            Popular movies according to Tmdb
            <div className="movieCardContainer">
              {data.length > 1 &&
                data.map((item) => {
                  return (
                    <MovieCard
                      key={item.id}
                      title={item.original_title}
                      description={item.overview}
                      rating={item.vote_average}
                      imageURL={item.poster_path}
                    />
                  );
                })}
              {loading && <h1>Loading....</h1>}
            </div>
          </header>
        </div>
      );
    }

    export default App;
ログイン後にコピー

データを取得し、それを小道具として MovieCard コンポーネントに渡しているコードをほぼ理解できます。

各映画の情報を表示するための MovieCard.js コンポーネントを作成します。

MoveCard.js

    import React from "react";

    export const MovieCard = ({ title, description, imageURL, rating }) => {

      const imagePath = `https://image.tmdb.org/t/p/w500${imageURL}`; // poster image path URL 

      return (
        <div className="movieCard">
          <img src={imagePath} height={400} />
          <div className="movieInfo">
            <h3>{title}</h3>
            <p>{description}</p>
            <p>{rating.toFixed(1)}⭐</p>
          </div>
        </div>
      );
    };
ログイン後にコピー

アプリケーションの CSS は次のとおりです:

App.css

    .App {
      text-align: center;
    }

    .App-header {
      background-color: #282c34;
      min-height: 100vh;
      display: flex;
      flex-direction: column;
      align-items: center;
      padding-top: 1em;
      font-size: calc(10px + 2vmin);
      color: white;
    }

    .movieCardContainer{
      margin-top: 1em;
      display: flex;
      flex-direction: column;
      gap: 1em;
      width: 60%;
      max-width: 800px;
    }

    .movieCard{
      display: flex;
    }

    .movieInfo{
      margin-left: 1em;
      text-align: left;
    }

    p{
      font-size: 18px;
    }
ログイン後にコピー

無限スクロール

さて、まず無限スクロールをどのように構築するかを理解しましょう。このために、スクロール バーの位置を見ていきます。スクロール バーの位置がページの終わりのすぐ上にある場合、読み込み状態を true に設定します。

ページの状態を 1 増やす別の useEffect を用意します。ページ番号が更新されると、そのページを依存関係として持つ最初の useEffect がトリガーされます。これにより、 fetchMovie() 関数が呼び出され、データが取得されます。

スクロールへの EventListner の追加

まず、スクロール バーの位置が変更されたことを知るために listen さえ追加します。

    window.addEventListener("scroll", handleScroll);
ログイン後にコピー

ハンドルスクロール

スクロールが発生すると、スクロール バーの現在の位置が Web ページの下部 (つまり、垂直方向のスクロール可能な領域の合計) のすぐ上にあるかどうかを確認します。 「はい」の場合、読み込み状態を true に変更します。

    const handleScroll = () => {
      if (document.body.scrollHeight - 300 < window.scrollY + window.innerHeight) {
        setLoading(true);
      }
    };
ログイン後にコピー
  • scrollHeight : 画面に表示されていない部分を含む、コンテンツの合計の高さを返すプロパティです。したがって、それはスクロール可能な領域の合計になります。
  • scrollY: ドキュメントを上から垂直方向にスクロールしたピクセル数を返すプロパティです。スクロールした部分になります。
  • innerHeight: ブラウザの Windows コンテンツ領域の高さを返すプロパティです。スクロールバーの幅になります。これは、コンテンツを渡したときではなく、コンテンツに到達したときにフェッチが行われるように、scrollY に追加されます。 ## useEffect

読み込み状態の変更に成功したら、ページ番号をインクリメントする useEffect を実装できます。これにより、ムービー データの取得が可能になります。

    useEffect(() => {
      if (loading == true) {
        setPage((prevPage) => prevPage + 1);
      }
    }, [loading]);

    // other useEffect that we already implemented

    useEffect(() => {
      fetchMovie();
    }, [page]);
ログイン後にコピー

EventListnerの最適化

スクロール中に handleScroll を複数回トリガーできるため、不要な関数の呼び出しが複数回発生します。関数にデバウンスを追加して、関数を呼び出すまでに時間がかかるようにすることができます。

    // debounce function
    function debounce(func, delay) {
      let timeoutId;
      return function (...args) {
        if (timeoutId) {
          clearTimeout(timeoutId);
        }
        timeoutId = setTimeout(() => {
          func(...args);
        }, delay);
      };
    }

    // adding debounce to the eventListner
    window.addEventListener("scroll", debounce(handleScroll, 500));
ログイン後にコピー

App.js の完全なコードは次のとおりです:

    import "./App.css";
    import { useState, useEffect } from "react";
    import axios from "axios";
    import { MovieCard } from "./MovieCard";

    function App() {
      const [page, setPage] = useState(1);
      const [data, setData] = useState([]);
      const [loading, setLoading] = useState(false);
      const fetchMovie = async () => {

        const URL = `https://api.themoviedb.org/3/movie/popular?language=en-US&page=${page}`;
        const data = await axios.get(URL, {
          headers: {
            Authorization:
              "Bearer API KEY",
            Accept: "application/json",
          },
        });
        setData((prevData) => [...prevData, ...data.data.results]);
        setLoading(false);
      };
      useEffect(() => {
        fetchMovie();
      }, [page]);

      const handleScroll = () => {
        if (
          document.body.scrollHeight - 300 <
          window.scrollY + window.innerHeight
        ) {
          setLoading(true);
        }
      };

      function debounce(func, delay) {
        let timeoutId;
        return function (...args) {
          if (timeoutId) {
            clearTimeout(timeoutId);
          }
          timeoutId = setTimeout(() => {
            func(...args);
          }, delay);
        };
      }

      window.addEventListener("scroll", debounce(handleScroll, 500));

      useEffect(() => {
        if (loading == true) {
          setPage((prevPage) => prevPage + 1);
        }
      }, [loading]);

      return (
        <div className="App">
          <header className="App-header">
            Popular movies according to Tmdb
            <div className="movieCardContainer">
              {data.length > 1 &&
                data.map((item) => {
                  return (
                    <MovieCard
                      key={item.id}
                      title={item.original_title}
                      description={item.overview}
                      rating={item.vote_average}
                      imageURL={item.poster_path}
                    />
                  );
                })}
              {loading && <h1>Loading....</h1>}
            </div>
          </header>
        </div>
      );
    }

    export default App;
ログイン後にコピー

これは、アプリケーションの動作を示す GIF です。

Building an Infinite Scroll Component in React

結論

React で無限スクロール コンポーネントを構築することは、非常に価値のある経験となる可能性があります。スクロールの仕組みについての理解が深まるだけでなく、状態管理、イベント リスナー、デバウンスなどの最適化テクニックについても学習できます。このガイドに従うことで、必要に応じてカスタマイズおよび改善できる基本的な無限スクロールのセットアップが完了しました。

映画データ、ブログ投稿、その他のコンテンツを表示する場合、このコンポーネントは強力な基盤として機能します。重要なのは、ユーザーがスクロールするときにデータがいつどのようにフェッチされるかを慎重に管理することで、スムーズなユーザー エクスペリエンスを確保することであることに注意してください。コーディングを楽しんでください!

以上がReact で無限スクロール コンポーネントを構築するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート