user7554217
user7554217

Reputation:

Apollo Client - fetchMore component update problem

In my NextJS application interfaced with a MongoDB API back-end - managed via GraphQL, I'm trying to implement the Apollo fetchMore feature, in order to update a component responsible to load more items from a data collection.

On page rendering, the component itself shows a "gallery" of 10 elements as its native functionality, populated via a GraphQL starting query. Then, I included a "load more" button to trigger the fetchMore function. The UX expects that if the user clicks the proper button, more 10 elements will going to be loaded in addition of the previous 10 - basically a classical async-infinite loading example.

By inspecting the app, I notice that both the queries are being returned successfully - the initialization one and the "load more 10 items" too managed by fetchMore - but the latter, after its execution, triggers the component's update that it's being re-initialized with the starter query instead of the fetchMore one.

To clarify it: on "load more" click, instead to see the next 10 gallery elements loaded - so to finally display a total of 20 - the component refreshes and displays the starter 10 elements, like its starting initialization - totally ignoring the fetchMore action, even if this one is being called, executed and received back with a populated 200 response.

Because this is my very first time in using it, I don't know if I'm missing something in my implementation, or I need to fix something. Anyway, here it goes:

Due to various reasons, I'm running the query in a parent component, then I pass the data as props to a child one:

Parent

// Initialization, etc.
[...]

const {loading: loadingIndex, error: errorIndex, data: dataIndex, fetchMore: fetchMoreIndex} = useQuery(ARTICLE_QUERY.articles.indexArticles, {
    // Last 30 days
    variables: {
      live: live,
      limit: 10
    }
  });

  // Exception check
  if (errorIndex) {
    return <ErrorDb error={errorIndex} />
  }
  // DB fetching check
  if (loadingIndex) {
    return (
      <section className="index-articles">
        <h6>Index - Articles</h6>
        <aside className="articles__loading">
          <h6>Loading</h6>
        </aside>
      </section>
    );
  }

  const articles = dataIndex.queryArticleContents;

  return (
    <IndexArticles labels={props.labels} articles={articles} fetchMore={fetchMoreIndex} />
  );

Child

// Initialization, etc.
[...]

let limit = 10; // My query hypothetically limiter
const IndexArticles = (props) => {
  useEffect(() => {
    // This is a getter method responsible to manage the ```fetchMore``` response
    getArticles(props.articles, props.fetchMore);
  });

return (
    <>
     // Component sections
    [...]

     // Load button
    {props.fetchMore &&
          <button className="articles__load" title={props.labels.index.title} tabIndex={40}>{props.labels.index.cta}</button>
        }
    </>
);

function getArticles(articles, fetchMore) {
  // Yes, I'm using jQuery with React. Just ignore it
  $('.articles__load').on('click tap', function(e) {
    e.preventDefault();

    $(this).addClass('hidden');
    $('.articles__loading').removeClass('hidden');

    fetchMore({
      variables: {
        // Cursor is being pointed to the last available element of the current collection
        lastLoaded: articles.length,
        limit: limit += 10
      },
      updateQuery: (prev, {fetchMoreResult, ...rest}) => {
        $('.articles__loading').addClass('hidden');
        $(this).removeClass('hidden');

        if (!fetchMoreResult) {
          return prev;
        }

        return {
          ...fetchMoreResult,
          queryArticleContents: [
            ...prev.queryArticleContents,
            ...fetchMoreResult.queryArticleContents
          ]
        }
      }
    });
  });
}

Anyone have experience with it or had experienced this case before?

Thanks in advance for the help

Upvotes: 1

Views: 5215

Answers (1)

user7554217
user7554217

Reputation:

As suggested on the official community, my configuration was missing about the notifyOnNetworkStatusChange: true in the query options, which is responsible to update the component and append the new data.

By changing the code in this way:

Parent


const {
  loading: loadingIndex, 
  error: errorIndex, 
  data: dataIndex, 
  // Add networkStatus property too in order to use notifyOnNetworkStatusChange properly
  networkStatus: networkStatusIndex
  fetchMore: fetchMoreIndex} = useQuery(ARTICLE_QUERY.articles.indexArticles, {
    // Last 30 days
    variables: {
      live: live,
      limit: 10
    },
    // Important for component refreshing with new data
    notifyOnNetworkStatusChange: true 
  });

The problem has been solved.

Upvotes: 1

Related Questions