我有一个查询GraphQL后端的组件,该组件返回作者的姓名和简历以及相关作者发布的所有帖子。我正在尝试对此处返回的帖子进行分页。我的查询如下:
query users($username: String!, $postLimit: Int!, $postStart: Int!) {
users(limit: 1, where: { username: $username }) {
_id
firstName
lastName
bio
posts(sort: "createdAt:DESC", limit: $postLimit, start: $postStart, where: {isPublished: true}) {
title
}
}
postsConnection(where: {isPublished: true}){
groupBy{
author{
key
connection{
aggregate{
count
}
}
}
}
}
}
运行此查询的组件正在使用Apollo Client:
// /components/blog/SingleAuthor.jsx
import withStyles from '@material-ui/core/styles/withStyles';
import PropTypes from 'prop-types';
import React from 'react';
import Loading from './Loading';
import { useQuery } from '@apollo/react-hooks';
import { NetworkStatus } from 'apollo-client';
import gql from 'graphql-tag';
import getUserQuery from '../../apollo/schemas/getUserQuery.graphql';
import Grid from '@material-ui/core/Grid';
import Head from 'next/head'
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import CircularProgress from '@material-ui/core/CircularProgress';
const styles = (theme) => ({
root: {},
});
export const GET_USER = gql`${getUserQuery}`;
export const getUserQueryVars = {
postStart: 0,
postLimit: 2,
};
const SingleAuthor = (props) => {
const {
classes,
authorSlug,
} = props;
const {
loading,
error,
data,
fetchMore,
networkStatus,
} = useQuery(
GET_USER,
{
// variables: {username: authorSlug},
variables: {username: authorSlug, ...getUserQueryVars},
// Setting this value to true will make the component rerender when
// the "networkStatus" changes, so we'd know if it is fetching
// more data
notifyOnNetworkStatusChange: true,
},
);
const loadingMorePosts = networkStatus === NetworkStatus.fetchMore;
const loadMorePosts = () => {
fetchMore({
variables: {
postStart: posts.length
},
updateQuery: (previousResult, { fetchMoreResult }) => {
if (!fetchMoreResult) {
return previousResult
}
// console.log('previousResult', previousResult);
// console.log('fetchMoreResult', fetchMoreResult);
let oldRes = {...previousResult};
let newRes = {...fetchMoreResult};
let oldPosts = oldRes.users[0].posts;
let newPosts = newRes.users[0].posts;
oldRes.users[0].posts = [...oldPosts, ...newPosts];
// console.log('Final result', oldRes);
return Object.assign({}, previousResult, {
// Append the new posts results to the old one
users: [...oldRes.users],
})
}
})
};
if (error) return <div>There was an error!</div>;
if (loading && !loadingMorePosts) return <Loading />;
const { users, postsConnection } = data;
const [user] = users;
const {
_id,
firstName,
lastName,
bio,
posts,
} = user;
const postCount = postsConnection.groupBy.author.find(({key}) => key === _id).connection.aggregate.count;
const areMorePosts = posts.length < postCount;
console.log('postCount', postCount);
console.log('areMorePosts', areMorePosts);
return (
<>
<Head>
<title>{`${firstName} ${lastName}`}</title>
<meta name="description" content={`Posts by ${firstName} ${lastName}`} key="postDescription" />
</Head>
<Grid item className={classes.root}>
<h1>{firstName} {lastName}</h1>
<p>{_id}</p>
<p>{bio}</p>
{posts.map((post) => {
return (
<h2>{post.title}</h2>
);
})}
{areMorePosts && (
<div className={classes.root}>
{loadingMorePosts ? (
<CircularProgress style={{opacity: 0.3}} />
) : (
<Button color="primary" className={classes.root} onClick={loadMorePosts}>Show more</Button>
)}
</div>
)}
</Grid>
</>
);
};
SingleAuthor.propTypes = {
classes: PropTypes.shape({
root: PropTypes.string,
}).isRequired,
};
export default withStyles(styles)(SingleAuthor);
如您所见,我目前正尝试一次使用load more
按钮仅返回2条帖子。单击此按钮后,将触发loadMorePosts()
方法,该方法将检索下2个帖子,依此类推。处理该方法时,该按钮将替换为加载进度图标(CircularProgress
)。
但是,这不起作用。该方法确实可以检索新帖子,但是不会触发UI的重新渲染,这会导致进度图标永久保留,并且检索到的帖子永远不会显示在浏览器中。该如何解决?
作为参考,回购位于https://github.com/amitschandillia/proost/blob/master/web,结果可以在https://www.schandillia.com/blog/authors/amitschandillia实时看到。
PS :可以在GraphQL端点https://dev.schandillia.com/graphql上测试查询。