中继游标连接规范says:
如果客户端未与hasNextPage
分页,
first
将为false, 或者如果客户端与first
分页,并且服务器具有 确定客户端已到达边缘集的末尾 由他们的游标定义。
我从该规范中理解的是,Relay只能在一个中分页 方向;前进或后退。对于无限而言,这似乎是合理的 滚动分页实现。
但是如何实现类似于stackoverflow问题页面的顺序页面导航 可以两种方式导航?
Relay.js适合这种分页吗?我不能依赖hasNextPage
和hasPreviousPage
这个永远不会有真正价值的字段,除非我对first
和last
进行分页,这也非常沮丧。
答案 0 :(得分:3)
我从该规范中了解到,中继只能单向,向前或向后分页。
正确。最初的设计正是如此,一个无限的滚动分页。它从未打算用于双向分页。
但是像stackoverflow问题页面的连续页面怎么样?
对于今天的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)*10
和10
是限制(开始后有多少项)。所以上面将取得21-30的记录。
请注意,您需要page
和limit
的初始值。所以你的最终查询将是:
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实现,因为它本质上为您提供双向导航,即使本机不支持。这种方法稍微优于第一种方法,但牺牲了直接跳转到页面的能力。
请注意,我们不能同时使用first
和last
:
强烈建议不要包含第一个和最后一个值,因为这可能会导致查询和结果混乱。
因此我们会正常构建我们的查询。类似的东西:
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')" />