继电器js的前后分页

时间:2017-03-14 09:50:23

标签: javascript reactjs graphql relayjs

中继游标连接规范says

  如果客户端未与hasNextPage分页,

first将为false,   或者如果客户端与first分页,并且服务器具有   确定客户端已到达边缘集的末尾   由他们的游标定义。

我从该规范中理解的是,Relay只能在一个中分页 方向;前进或后退。对于无限而言,这似乎是合理的 滚动分页实现。

但是如何实现类似于stackoverflow问题页面的顺序页面导航 可以两种方式导航?

Relay.js适合这种分页吗?我不能依赖hasNextPagehasPreviousPage这个永远不会有真正价值的字段,除非我对firstlast进行分页,这也非常沮丧。

2 个答案:

答案 0 :(得分:3)

  

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

正确。最初的设计正是如此,一个无限的滚动分页。它从未打算用于双向分页。

  

但是像stackoverflow问题页面的连续页面怎么样?

对于今天的Relay默认实现,这是非常棘手的,因为如上所述,它不是为双向导航而设计的。

那就是说,你可以仍然实现这一点,尽管不是通过最佳方式。

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

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

示例

假设您有一个显示成员列表的视图。您使用member获取memberList个节点的列表。如果您只想显示每个"页面"我们在第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,
  });
}

方法2 - 手动管理游标

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

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

  

强烈建议不要包含第一个和最后一个值,因为这可能会导致查询和结果混乱。

因此我们会正常构建我们的查询。类似的东西:

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

$cursor的初始值为null

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

这样,无论何时向后导航,只需弹出堆栈中的最后一个光标,并将其用于after参数。它在您的应用程序中需要一些额外的逻辑,但这绝对可行。

答案 1 :(得分:1)

基于@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')" />