無限のスクロールと


このHackathonに参加することによって、私は技術的にAPIを構築する方法を学びました.私はアポロ法などを発見していますfetchMore 私はそれが超クールだと思う!
だから、私は念願のアプリの心の中に持っていた機能の一つは無限スクロールです.私は多くのダムデータを持っていませんが、私はまだこれが新しいthingi - i ' sを学ぶのが大好きです.
これを実行する方法の調査の中で、アポロのfetchMore それは完全に私の要求に合っています.
すぐにこのプロジェクトを開始するにはジャンプするには、“安い”私はできるように、私はデータベースとしてMongoDBのアトラスを使用することを決めたので、私はDBについて多くの心配し、残りに集中する必要はありません.つのアプリケーションの要件の1つは、ユーザーの位置によって(最初にFarthestに近い)、その後、最近の日付で投稿をソートすることです.
私は自由層クラスタを使用することを選んだので、aggregate or mapReduce それは私が理想的に使うものです.しかし、まあ、私はJavaScriptのメソッドを使用する必要があります迅速かつ簡単ですが、演奏者としてではなく😅.
それでは、始めましょう.まず、GQLクエリをGET_POSTS そして、アポロのuseQuery ページがマウントされたときにポストを取得します.
  const GET_POSTS = gql`
    query GetPosts($offset: Int) {
      posts(offset: $offset) {
        content {
          ...
        }
        hasMore
      }
    }
  `;

    const { loading, error, fetchMore } = useQuery(GET_POSTS, {
    onCompleted: data => {
      const { content, hasMore } = data.posts;
      setPosts(content);
      setHasMorePosts(hasMore);
    },
  });
注意fetchMore usequeryで破壊されたプロパティでは?これはアポロによって基本的にGraphSQLクエリを再利用するために与えられた関数/メソッドですが、変数を渡すのは自由です.
私が欲しいものは、ユーザーがスクロールして、ページの底に達するとき、私はより多くのポストを得たいです.ここでオフセットが入るところです.私はonScroll 私が添付したイベントdiv そのようなポストを含む
<div onScroll={onScroll}>...</div>
そして、実装のためのコードです
  const onScroll = e => {
    // if div is at the bottom, fetch more posts
    if (e.target.scrollTop + e.target.clientHeight === e.target.scrollHeight) {
      // if there are no more posts to fetch, don't do anything
      if (!hasMorePosts) return;

      setTimeout(() => {
        setIsFetchMoreLoading(true);
        fetchMorePosts();
      }, 300);

      return;
    }
  };

  const fetchMorePosts = async () => {
    setOffset(prev => prev + 1);

    const fetchedMore = await fetchMore({
      variables: { offset: offset + 1 },
    });

    const { content, hasMore } = fetchedMore.data.posts;
    setPosts(previousPosts => [...previousPosts, ...content]);
    setHasMorePosts(hasMore);
    setIsFetchMoreLoading(false);
  };
それはかなり簡単です.The onScroll イベントはスクロールイベントを聞きます、そして、ユーザーがページの底にあるならば、私はより多くのポストを得たいです.しかし、取得するより多くのポストがないならば、私はちょうど戻りたいです、そして、何もしません.
fetchMorePosts 関数は、アポロの呼び出しfetchMore 新しいオフセット変数を指定します.今、リゾルバで何が起こっているかを示します.
const resolvers = {
  Query: {
    posts: async (_parent, { offset }, { db, loggedUser }, _info) => {
      if (!loggedUser) throw new AuthenticationError('you must be logged in');

      const { location } = await db.collection('users').findOne({ username: loggedUser.username });

      let posts;

      const allPosts = await db
        .collection('posts')
        .find()
        .toArray();

      const sortedByDate = allPosts.reverse();

      // mongodb mapReduce not supported for free tier cluster :(
      // Workaround -> handle sort using JS methods

      if (location) {
        const compareDistance = (postLat, postLng) => calcDistance(postLat, postLng, location.lat, location.lng);
        // sort by distance (closest -> farthest)
        posts = sortedByDate.sort(
          (a, b) => compareDistance(a.location.lat, a.location.lng) - compareDistance(b.location.lat, b.location.lng)
        );
      } else {
        posts = sortedByDate;
      }

      // sort by offset

      if (offset) {
        // if offset is not null (not the initial fetch)
        const newOffsetValue = offset * FETCH_LIMIT;
        const payload = posts.slice(newOffsetValue, FETCH_LIMIT + newOffsetValue);

        return { content: payload, hasMore: !!payload.length };
      } else {
        const payload = posts.slice(0, FETCH_LIMIT);

        return { content: payload, hasMore: !!payload.length };
      }
    }
  }
}
オフセットは、どこから始めたいのか、制限するかということです.したがって、オフセットが未定義である最初のフェッチでif(offset) 他のブロックは、0からの投稿を制限したいと思います.から次のクエリfetchMore のオフセットを与える1 , で、配列をスライスします(5,10) .
また帰りますhasMore フロントエンド側のフェッチをより多くの状態にしたい場合の応答で.
私は多くを学びました.私が反応してコード化した時から、それもしばらくありました.フェアゲーム.間違いなく、サーバー上のDBをソートし、クライアント上でUIを処理するより効率的な方法があります(アポロのInmemoryCacheの代わりに反応状態を使用することを選んだ).おそらく多くの時間とリソースを使うと、これらのことは改善されます.
それまで、ハッピーハッキング!🚀