【问题标题】:Forward and backward pagination with relay js使用中继js进行正向和反向分页
【发布时间】:2017-08-04 14:08:08
【问题描述】:

中继游标连接规范says:

如果客户端没有使用first 进行分页,hasNextPage 将为 false, 或者如果客户端使用first 进行分页,并且服务器有 确定客户端已到达边集的末尾 由它们的光标定义。

我从该规范中了解到,Relay 只能分页 方向;向前或向后。这对于 infinite 来说似乎是合理的 滚动分页实现。

但是如何实现类似于stackoverflow问题页面的顺序页面导航? 可以双向导航吗?

Relay.js 适合这种分页吗?我不能依赖 hasNextPagehasPreviousPage 字段,除非我使用 firstlast 进行分页,这也很不鼓励。

【问题讨论】:

    标签: javascript reactjs graphql relayjs


    【解决方案1】:

    我从该规范中了解到,中继只能以单向分页,向前或向后。

    正确。原来的设计就是这样,无限卷轴分页。它从未打算用于双向分页。

    但是像 stackoverflow 问题页面这样的顺序页面呢?

    这对于 Relay 目前的默认实现来说是相当棘手的,因为如上所述,它不是为双向导航而设计的。

    也就是说,您仍然可以做到这一点,尽管不是通过最佳方式。


    方法一 - 通过 Relay 传递页面信息

    这可能是最容易实现的方法,尽管不是最理想的方法。它涉及将页面信息作为 GraphQL 参数传递给 Relay。每次导航到新页面时,这都需要一个新的中继查询。

    示例

    假设您有一个显示成员列表的视图。您使用memberList 获取member 节点列表。如果您只想在每个“页面”显示 10 个成员并且我们在第 3 页,您可以这样做:

    app: () => Relay.QL`
      fragment on App {
        memberList(page: 3, limit: 10) {
          ...
        }
      }`
    }
    

    在您的后端,您的 SQL 查询现在看起来像:

    SELECT id, username, email FROM members LIMIT 20, 10;
    

    其中20 是开始记录:(page-1)*1010 是限制(开始后的项目数)。所以上面将获取 21-30 的记录。

    请注意,您需要 pagelimit 的初始值。所以你的最终查询是:

    prepareVariables() {
      return {
        page: 1,
        limit: 10,
      };
    },
    fragments: {
      app: () => Relay.QL`
        fragment on App {
          memberList(page: $page, limit: $limit) {
            ...
          }
        }`
      }
    }
    

    当导航到新页面时,我们需要更新值:

    _goToPage = (pg) => {
      this.props.relay.setVariables({
        page: pg,
      });
    }
    

    方法二——手动管理游标

    这是一个有点 hacky 的实现,因为它本质上为您提供了双向导航,即使它本身并不支持。这种方法比第一种方法稍微好一点,但牺牲了直接跳转到页面的能力。

    请注意,我们不能同时使用firstlast

    强烈建议不要同时包含 first 和 last 的值,因为这可能会导致混淆查询和结果。

    因此我们将正常构建查询。比如:

    app: () => Relay.QL`
      fragment on App {
        memberList(first: 10, after: $cursor) {
          ...
        }
      }`
    }
    

    $cursor 的初始值为null

    当您导航到下一页并将$cursor 的值设置为最后一个成员节点的光标时,您还将该值保存在本地堆栈变量中。

    这样,每当您返回时,您只需从堆栈中弹出最后一个光标并将其用于您的after 参数。它需要在您的应用程序中添加一些额外的逻辑,但这绝对是可行的。

    【讨论】:

    • 所以在方法2中,如果栈为空,则表示没有上一页了。 hasNextPage 变量会告诉我们是否没有更多的 nextPage。是这样吗?
    【解决方案2】:

    基于@Chris给出的方法2

    这是我在 VueJS 中的解决方案,对于 ReactJS 也大致相同。

        loadPage(type) {
          const { endCursor } = this.pageInfo
          let cursor = null 
          if(type === 'previous') {
            this.cursorStack = this.cursorStack.slice(0, this.cursorStack.length - 1)
            cursor = this.cursorStack[this.cursorStack.length - 1]
          }
          else {
            cursor = endCursor
            this.cursorStack = [...this.cursorStack, cursor]
          }
          this.fetchMore({
            variables: { cursor: cursor },
            updateQuery: (previousResult, { fetchMoreResult }) => {
              if (!fetchMoreResult) return previousResult
              return fetchMoreResult
            }
          })
        },
    

    在模板中:

    <button :disabled="!cursorStack.length" @click="loadPage('previous')" />
    <button :disabled="!pageInfo.hasNextPage" @click="loadPage('next')" />
    

    【讨论】:

      猜你喜欢
      • 2012-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-10
      • 1970-01-01
      • 2021-03-24
      相关资源
      最近更新 更多