react-apollo的data.refetch()函数如何工作

时间:2017-06-30 06:16:33

标签: reactjs graphql apollo react-apollo

在前端,我正在使用ReactJS并尝试在列表视图中内置过滤选项。列表视图通过发出此graphql查询正确地从graphql端点获取数据:

query getVideos($filterByBook: ID, $limit: Int!, $after: ID) {
    videosQuery(filterByBook: $filterByBook, limit: $limit, after: $after) {
        totalCount
        edges {
            cursor
            node {
                id
                title
                ytDefaultThumbnail
            }
        }
        pageInfo {
            endCursor
            hasNextPage
        }
    }
}

在初始加载$filterByBook变量设置为null时,查询会正确返回所有节点的所有页面(查询返回分页结果)。然后,通过单击过滤器(按书籍过滤)发出另一个graphql查询,但它始终返回相同的data。以下是过滤组件

的代码段
  renderFilters() {
    const { listOfBooksWithChapters, refetch } = this.props;

    return (
      <Row>
        <FilterBooks
          onBookTitleClickParam={(onBookTitleClickParam) => {
            return refetch({
              variables: {
                limit: 3,
                after: 0,
                filterByBook: onBookTitleClickParam
              }
            })
          }}
          listOfBooksWithChapters={listOfBooksWithChapters}
        />
      </Row>
    )
  }

而且,这里是没有列表视图组件导入的完整代码

class VideoList extends React.Component {
  constructor(props) {
    super(props);

    this.subscription = null;
  }

  componentWillUnmount() {
    if (this.subscription) {
      // unsubscribe
      this.subscription();
    }
  }

  renderVideos() {
    const { videosQuery } = this.props;

    return videosQuery.edges.map(({ node: { id, title, ytDefaultThumbnail } }) => {
      return (
        <Col sm="4" key={id}>
          <Card>
            <CardImg top width="100%" src={ytDefaultThumbnail} alt="video image" />
            <CardBlock>
              <CardTitle>
                <Link
                  className="post-link"
                  to={`/video/${id}`}>
                  {title}
                </Link>
              </CardTitle>
            </CardBlock>
          </Card>
        </Col>
      );
    });
  }

  renderLoadMore() {
    const { videosQuery, loadMoreRows } = this.props;

    if (videosQuery.pageInfo.hasNextPage) {
      return (
        <Button id="load-more" color="primary" onClick={loadMoreRows}>
          Load more ...
        </Button>
      );
    }
  }

  renderFilters() {
    const { listOfBooksWithChapters, refetch } = this.props;

    return (
      <Row>
        <FilterBooks
          onBookTitleClickParam={(onBookTitleClickParam) => {
            return refetch({
              variables: {
                limit: 3,
                after: 0,
                filterByBook: onBookTitleClickParam
              }
            })
          }}
          listOfBooksWithChapters={listOfBooksWithChapters}
        />
      </Row>
    )
  }


  render() {
    const { loading, videosQuery } = this.props;

    if (loading && !videosQuery) {
      return (
        <div>{ /* loading... */}</div>
      );
    } else {
      return (
        <div>
          <Helmet
            title="Videos list"
            meta={[{
              name: 'description',
              content: 'List of all videos'
            }]} />
          <h2>Videos</h2>
          {this.renderFilters()}
          <Row>
            {this.renderVideos()}
          </Row>
          <div>
            <small>({videosQuery.edges.length} / {videosQuery.totalCount})</small>
          </div>
          {this.renderLoadMore()}
        </div>
      );
    }
  }
}

export default compose(
  graphql(VIDEOS_QUERY, {
    options: () => {
      return {
        variables: {
          limit: 3,
          after: 0,
          filterByBook: null
        },
      };
    },
    props: ({ data }) => {
      const { loading, videosQuery, fetchMore, subscribeToMore, refetch } = data;
      const loadMoreRows = () => {
        return fetchMore({
          variables: {
            after: videosQuery.pageInfo.endCursor,
          },
          updateQuery: (previousResult, { fetchMoreResult }) => {
            const totalCount = fetchMoreResult.videosQuery.totalCount;
            const newEdges = fetchMoreResult.videosQuery.edges;
            const pageInfo = fetchMoreResult.videosQuery.pageInfo;

            return {
              videosQuery: {
                totalCount,
                edges: [...previousResult.videosQuery.edges, ...newEdges],
                pageInfo,
                __typename: "VideosQuery"
              }
            };
          }
        });
      };
      return { loading, videosQuery, subscribeToMore, loadMoreRows, refetch };
    }
  }),
  graphql(LIST_BOOKS_QUERY, {
    props: ({ data }) => {
      const { listOfBooksWithChapters } = data;
      return { listOfBooksWithChapters };
    }
  }),
)(VideoList);

问题:

为什么refetch函数在不考虑新变量filterByBook的情况下返回数据?如何检查我提供给variables函数的refetch对象?我是否需要将从refetch功能收到的数据重新映射回组件props

修改

我找到了查找我提供给查询的variable对象的方法,并发现过滤事件上的variable对象返回此数据

variables:Object
    after:0
    limit:3
        variables:Object
        after:0
        filterByBook:"2"
        limit:3

1 个答案:

答案 0 :(得分:2)

似乎refetch函数并不意味着重新设置具有不同变量集的数据(请参阅此discussion)。

我终于在this article

的帮助下成功解决了我的问题