如何用Apollo客户端的fetch more和react实现无限滚动的实例

327 阅读4分钟

图片来自github.com/apollograph…

目的

我最近用Apollo客户端实现了无限滚动,我花了一些时间,我将与你分享,以避免浪费时间。此外,我想通过使用Apollo服务器创建自己的假数据,希望这也是有帮助的。

什么是Apollo客户端?

Apollo客户端是一个用于JS的综合状态管理库。在这篇文章中,我将用反应来解释。最重要的部分是缓存,可以避免从服务器端获取不必要的数据。这个库非常有用,因为它不仅可以通过缓存获取数据,更新数据,还可以作为一个状态管理库使用,比如Redux, Recoil, Zustand。

什么是Apollo服务器?

Apollo服务器是一个开源的库,可以连接所有你想连接的东西。

下面的图片来自官方文档,这个图片说明了什么是Apollo服务器。

图片来自www.apollographql.com/docs/apollo…

在这篇文章中,我将更多地关注例子。让我们深入了解一下这个例子。

注意。你可以选择基于偏移量的分页或基于光标的分页。这不是本文的主要焦点,但使用情况是不同的。就无限滚动而言,你可以使用两种方式,我使用基于偏移量的方式,因为它比其他方式更简单。

例子

前半部分。后台Apollo服务器

  1. 创建你的项目(项目名称由你决定)
mkdir apollo-inifinite-scroll-backend
cd apollo-inifinite-scroll-backend

2.用npm初始化node.js项目。如果你想推送github,你需要创建.gitignore文件并写入 "node_modules"(可选)。你的项目包含 "package.json "文件

npm init -y

3.安装一些依赖项并创建一个基础索引文件

npm install apollo-server graphql
touch index.js

4.定义你的graphql模式和解析器。为了更简单,我遵循简单的例子(书籍)。但你想改变你想使用的任何东西。你需要把offset和limit传给query类型,并通过使用resolver创建offset和limit的逻辑。最后,有必要通过使用这两个来创建一个服务器。

import { ApolloServer, gql } from "apollo-server";
import { bookBasic } from "./data/books.js";

const typeDefs = gql`
 
  type Book {
    title: String
    author: String
  }
  type Query {
    books(offset: Int, limit: Int): [Books!]
  }
`;

const resolvers = {
  Query: {
    books: async (_parent, args, _context, _info) => {
      if (args.limit) {
        const start = args.offset;
        const end = args.limit;
        return [...booksBasic].slice(start, end);
      } else {
        return [...booksBasic];
      }
    },
  },
};

new ApolloServer({
  typeDefs,
  resolvers,
})
  .listen()
  .then(({ url }) => {
    console.log(`🚀  Server ready at ${url}`);

5.像下面这样创建你的数据。

export const booksBasic = [
  {
    title: "Book1",
    author: "John",
  },
  {
    title: "Book2",
    author: "Mike",
  },
  {
    title: "Book3",
    author: "John",
  },
... same structure, I omitted it(but I have 36 books data)

6.在你的终端上使用下面的命令运行服务器,你会看到下面的句子。

node index.js
🚀 Server ready at http://localhost:4000/

7.访问 "localhost:4000",你可以看到如下图所示的屏幕

8.点击上面屏幕上的 "查询你的服务器 "按钮,你就可以使用graphql的沙盒了!!这次我们有书的标题和作者,所以你可以写一个如下图的查询。

9.你可以通过使用offset和limit来设置范围。基本上offset意味着 "开始",limit意味着 "结束"。因此,如果你想从10到20的图片中挑选,你可以设置偏移量10,限制量10,如下图所示。

好了,我们已经完成了后台的工作。所以我将创建一个前台。

下半部分。前端Apollo客户端

  1. 使用create react app来设置你的环境(项目名称是可选的)。
npx create-react-app apollo-inifinite-scroll-frontend
cd apollo-inifinite-scroll-frontend

2.2.安装一些依赖项。我使用react-insersection-observer来检查和重新获取浏览器屏幕是否在底部,但你也可以使用另一个(例如,你可以自己写处理滚动,或使用react-infinite-scroller-component)。

npm install @apollo/client graphql react-intersection-observer

3.在index.js中设置你的apollo客户端,如下所示。你需要通过使用 "offsetLimitPagination "将缓存类型策略设置为使用基于偏移量的分页。然后创建一个新的客户端,并设置Uri和缓存。注意,这个URI是 "apollo server uri",我们在前半部分创建了Apollo服务器。最后,你需要用新的客户端将你的应用程序与apollo提供者包装起来。

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { ApolloProvider, ApolloClient, InMemoryCache } from "@apollo/client";
import { offsetLimitPagination } from "@apollo/client/utilities";

const cache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        books: offsetLimitPagination(),
      },
    },
  },
});

const client = new ApolloClient({
  uri: "http://localhost:4000/",
  cache,
});

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>

4.创建你的查询,从后端获取数据。由于我们在Apollo服务器上创建了书籍、标题和作者查询。你可以像下面这样创建查询。

import { gql } from "@apollo/client";

export const GET_BOOKS = gql`
  query getBooks($offset: Int, $limit: Int) {
    books(offset: $offset, limit: $limit) {
      title
      author
    }
  }
`;

5.创建app.js来显示查询。我将解释Card部分,所以不用担心。你需要导入你在第4步中创建的查询,并用useQuery来使用它。你可以得到一些值,如data,fetchmore。在这种情况下,data和fetch more是必须的,加载和错误是可选的。你还需要设置变量和偏移量、限制。正如我已经解释过的,offset是开始,limit是结束,所以在这段代码中每次加载8张卡片。你可以把你的数据映射到卡片上,并使用inview来观察浏览器是否有底气去获取更多的书籍卡片。在这种情况下,我扩展了一个限制,每次取更多。

import { useQuery } from "@apollo/client";
import { Card } from "./components/Card";
import { GET_BOOKS } from "./graphql/queries/books";
import { InView } from "react-intersection-observer";

export default function App() {
  const { loading, error, fetchMore, data } = useQuery(GET_BOOKS, {
    variables: { offset: 0, limit: 8 },
  });

  if (loading) {
    return <p>Loading</p>;
  }
  if (error) {
    console.log(error);
  }

  if (data) {
    console.log(data.books.length);
  }

  return (
    <div>
      {data &&
        data.books.map(({ title, author }, index) => (
          <Card key={index} title={title} author={author} />
        ))}
      {data && (
        <InView
          onChange={async (inView) => {
            const currentLength = data.books.length || 0;
            if (inView) {
              await fetchMore({
                variables: {
                  offset: currentLength,
                  limit: currentLength * 2,
                },
              });
            }
          }}
        />
      )}
    </div>
  )

6.创建一个卡片。这一部分完全由你决定,你可以创建卡片,图片,...等等。你也可以设计它。在我的案例中,我使用了模块css和scss。然而,这完全是可选的。

import React from "react";
import style from "./style.module.scss";

export const Card = React.memo(function (props) {
  const {
    title,
    author,
  } = props;

  return (
    <div className={style.container}>
      <p>{title}</p>
      <p>{author}</p>
    </div>
  );
})

7.完成了!你可以看到下面这样的屏幕。很难找到工作,所以我设置了console.log关于数据长度。你可能会注意到,长度的数量每8个增加,这意味着工作完美!!!。很好!!!。

总结

在这篇文章中,我分享了如何使用fetch more的知识,以及如何通过使用自己创建的真正的端点来实现无限滚动。事实上,fetch more功能并不古老,所以我很难找到合适的信息。我花了很多时间去搜索和尝试,所以我希望这篇文章能帮助你,避免浪费时间。

参考资料

官方文档(阿波罗服务器):https://www.apollographql.com/docs/apollo-server/

官方文档(阿波罗客户端):https://www.apollographql.com/docs/react/

Apollo客户端的分页和无限滚动:www.apollographql.com/blog/apollo…

如何用GraphQL和React实现无限滚动:sysgears.com/articles/ho…

React + GraphQL + Apolloで無限のスクロール(Offset-based):qiita.com/sinno999/it…

GraphQLのページネーション機能を実装する方法:Apollo client + express-graphql:sterfield.co.jp/programmer/…

谢谢您的阅读!!