question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

subscribeToMore causes the initial request to be refetched

See original GitHub issue

Hello,

I’m setting up a quite simple message feed on my app. There is an infinite scroll that uses the fetchMore function with a cursor pagination logic and a subscribeToMore to listen for new messages.

I can succeed to make the apollo working for fetching more OR subscription but not for both…

This is my initial query:

    messageFeed(id: $id, cursor: $cursor) {
      messages {
        id
        value
      }
      cursor
    }

This is my merging function:

typePolicies: {
  Query: {
    fields: {
      messageFeed: {
        keyArgs: false,
        merge(existing, incoming) {
          let messages
          if (existing) {
            messages = [...existing.messages, ...incoming.messages];
          } else {
            messages = incoming.messages;
          }
          return {
            cursor: incoming.cursor,
            messages
          }
        }
      }
    }
  }
}

So if I stop here, it is working fine. The merging is well executed and I got an infinite flow of messages while I’m scrolling down.

Here come the subscription and the issues…

This is my subscribeToMore function:

    subscribeToMore({
      document: NEW_MESSAGE_SUBSCRIPTION,
      variables: {
          discussionId: discussionID
      },
      updateQuery: (prev, { subscriptionData }) => {
        if (!subscriptionData.data) return prev;
        const newMessage = subscriptionData.data.message;
        return  {
          messageFeed: {
            messages: [newMessage]
          }
        };
      }
    })

When a new message is posted, here what happening on the DOM:

initial 20 first messages new message from the subscription again initial 20 first messages

When debugging, I noticed the merge function is called twice.

First call (when the subscription is fired) existing => the first 20 messages already displayed in the DOM incoming => the new message from the subscription merge => the two are merged and the 21 messages are well returned.

It should stop here.

BUT then, a new graphql post (with the same variables as the initial request at page load) is coming from nowhere which cause the merge function to be called again:

existing => the 21 messages already displayed in the DOM incoming => the same 20 messages as the initial request merge => the two are merge and the 41 and returning (including 20 duplicates)

Any idea from where is coming that second call?

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:2
  • Comments:12 (1 by maintainers)

github_iconTop GitHub Comments

4reactions
FedeBevcommented, Apr 19, 2021

In a situation without a pagination to deal with, setting nextFetchPolicy: 'cache-first', as suggested by @LovingGarlic, works perfectly.

1reaction
LovingGarliccommented, Apr 28, 2021

First I went through and made sure that both my updateQuery and my merge functions recreate their respective objects exactly including __typename fields.

@LovingGarlic Would you mind share the code here?

Essentially it’s something like this:

merge(existing, incoming, { args }) {
    if (!incoming) {
      return [];
    }

    if (!existing || !args.paginationArgs.before) {
      return incoming;
    }

    return {
      __typename: existing.__typename,
      pageInfo: {
        ...incoming.pageInfo,
      },
      edges: args.paginationArgs.before
        ? [...incoming.edges, ...existing.edges]
        : [...existing.edges, ...incoming.edges],
    };
},

Note in the second conditional, that I check for the existence of a before cursor (my pagination only goes one direction). This is to determine if the merge was triggered by a fetchMore or a subscription as mentioned above. The notice in the last return, making sure to add the __typename field to the returned object (this seems necessary for the cache to be updated properly), then building out the pageInfo and edges. A similar strategy would be needed for the updateQuery.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Queries - Apollo GraphQL Docs
If you provide new values for some of your original query's variables but not all of them, refetch uses each omitted variable's original...
Read more >
How to refetch a query when a new subscription arrives in ...
I tried both using Subscription component and subscribeToMore to call "refetch" method in Query's child component but both methods cause ...
Read more >
Building Chatty — Part 6: GraphQL Subscriptions - Medium
This will keep request execution more reliable and the WebSocket connection ... First, we'll use apollo-server to create a PubSub manager.
Read more >
A comprehensive guide to GraphQL with Apollo Client in React
A client requests resources from a GraphQL server using a GraphQL query. ... First, you'll generate a query using a tool like Apollo...
Read more >
Subscriptions and Live Queries - Real Time with GraphQL
The first major and wide-adopted transport implementation was (and ... Of course, in a real-world application we would like to subscribe to ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found