Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

On the frontend, I am using ReactJS and trying to build-in a filtering option to a list view. The list view correctly getting data from graphql endpoint by issuing this graphql query:

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
        }
    }
}

On the initial load $filterByBook variable is set to null, so the query correctly returns all pages for all nodes (query returns a paginated result). Then, by clicking on the filter (filter by book) another graphql query is issuing, but it always returns the same data. Here is a code snippet for filtering component

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

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

And, here is complete code without imports for the list view component

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);

Question:

Why refetch function returns data without taking into account new variable filterByBook? How to check which variables object I supplied to the refetch function? Do I need to remap data that I receive from refetch function back to the component props?

EDIT:

I found the way to find what variable object I supplied to the query and found that variable object on filtering event returns this data

variables:Object
    after:0
    limit:3
        variables:Object
        after:0
        filterByBook:"2"
        limit:3
like image 588
SaidAkh Avatar asked Oct 18 '22 10:10

SaidAkh


2 Answers

It seem that refetch function is not meant to refetch data with different variables set (see this discussion).

I finally and successfully solved my issue with the help from this article

like image 36
SaidAkh Avatar answered Oct 21 '22 08:10

SaidAkh


you can do it by adding refetch in useQuery

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

then call function refetch()

 const saveChange = input => {
               refetch();

    };

OR

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

            variables: {
                createBacklogInput: {
                    backlogTitle: backlogInput,
                   project:id
                }
            }
        }).then(refetch);
like image 184
L3xpert Avatar answered Oct 21 '22 08:10

L3xpert