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

How data.refetch() function from react-apollo works

在前端,我正在使用 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,因此查询正确 returns 所有节点的所有页面(查询 returns 一个分页结果)。然后,通过单击过滤器(按书籍过滤)另一个 graphql 查询发出,但它总是 returns 相同 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 函数 returns 数据不考虑新变量 filterByBook?如何检查我向 refetch 函数提供了哪个 variables 对象?我是否需要将从 refetch 函数收到的数据重新映射回组件 props

编辑:

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

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

似乎 refetch 函数并不意味着重新获取具有不同变量集的数据(参见此 discussion)。

this article

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

你可以通过在 useQuery

中添加 refetch 来实现
 const {loading, data, error,refetch} = useQuery(GET_ALL_PROJECTS,
        {
            variables: {id: JSON.parse(localStorage.getItem("user")).id}
        });

然后调用函数refetch()

 const saveChange = input => {
               refetch();

    };

const saveChange = input => {
        setIsOpen(false);
        addProject({

            variables: {
                createBacklogInput: {
                    backlogTitle: backlogInput,
                   project:id
                }
            }
        }).then(refetch);