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

Posted

技术标签:

【中文标题】react-apollo 中的 data.refetch() 函数如何工作【英文标题】:How data.refetch() function from react-apollo works 【发布时间】:2017-12-04 00:29:02 【问题描述】:

在前端,我正在使用 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。这是过滤组件的代码sn-p

  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  src=ytDefaultThumbnail  />
            <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?如何检查我提供给refetch 函数的variables 对象?我是否需要将从refetch 函数接收到的数据重新映射回组件props

编辑:

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

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

【问题讨论】:

【参考方案1】:

你可以通过在 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);

【讨论】:

【参考方案2】:

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

在this article的帮助下,我终于成功地解决了我的问题

【讨论】:

以上是关于react-apollo 中的 data.refetch() 函数如何工作的主要内容,如果未能解决你的问题,请参考以下文章

React-Apollo - 查询 - renderProp:反应警告:无法对未安装的组件执行反应状态更新

React-Apollo,不要在组件加载时运行查询

react-apollo 突变不会重新获取

使用 react-apollo 自定义 InputTypes

react-apollo 没有连接到我的 graphql 本地服务器

react-apollo中动态改变查询的解决方案