ApolloClient的updateQuery不会使用新数据重新渲染组件

时间:2019-09-30 13:44:56

标签: reactjs graphql apollo-client

我有一个查询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上测试查询。

0 个答案:

没有答案