React query and subscription cache

Hi,

We’re using Apollo in react to use both queries and subscription with a Hasura backend server- as per the instructions here - see the code below. This seems to work fine, but we see that the cache is not shared between the query results and the subscription results.

Is there any way possible to share the cache between queries and subscriptions? I could not find any information about this.

thx,

Robert

export const ApolloClientProvider = ({ children }: ApolloClientProviderProps): JSX.Element => {
  const { getAccessTokenSilently } = useAuth0();
  const apolloClient = useRef<ApolloClient<NormalizedCacheObject>>();
  const timeoutLink = new ApolloLinkTimeout(graphqlApiConfig.defaultTimeout);
  const httpLink = new HttpLink({ uri: `${graphqlApiConfig.host}${graphqlApiConfig.graphqlEndpoint}` });

  const timeoutHttpLink = timeoutLink.concat(httpLink);
  const fetchToken = async (): Promise<string | void> => {
    try {
      return await getAccessTokenSilently();
    } catch (error: unknown) {
      console.error('Failed to fetch token', error);
    }
  };

  const authHttpLink = setContext(async (_, { headers, ...rest }) => {
    const token = await fetchToken();
    if (!token) return { headers, ...rest };
    return { ...rest, headers: { ...headers, authorization: `Bearer ${token}` } };
  });

  const fullHttpLink = authHttpLink.concat(timeoutHttpLink);

  const client = createClient({
    url: `${graphqlApiConfig.wsHost}${graphqlApiConfig.graphqlEndpoint}`
  });
  const wsLink = new GraphQLWsLink(client);

  const splitLink = split(
    ({ query }) => {
      const definition = getMainDefinition(query);
      return definition.kind === 'OperationDefinition' && definition.operation === 'subscription';
    },
    wsLink,
    fullHttpLink
  );

  if (!apolloClient.current) {
    apolloClient.current = new ApolloClient({
      link: splitLink,
      cache: new InMemoryCache({})
    });
  }

  return <ApolloProvider client={apolloClient.current}>{children}</ApolloProvider>;
};

Hey @Notalifeform :wave:

Unless you’re creating multiple clients in your app, you should be using the same cache for all operations. Do you have the Apollo Client Devtools installed by chance? This makes it easier to inspect the cache. Could you see if you’re seeing anything written there? This should also help you detect if you’re creating a single instance or not.

Thx @jerelmiller for the quick response.

After inspection I do see that we have one client and that the cache is indeed shared. We’re also requesting aggregations form the server, which I expected to be read form the cache too - but those do not end up in the object cache, since they are not entities with an id - but they do end up in the query cache - correct?
This means when we switch our application form fetching to subscriptions (a user option) the subscriptions have to be collected once before we can display them.
While I do like the push based principle of subscriptions it introduces a bunch of challenges (both client and server-side), so I guess I’ll the follow advice in the apollo docs to use polling instead.

thx.

Robert

Even if you name them equally, the cache cannot just assume that the query users has the same contents as the subcription users - they could be two completely different things with just the same name. So unless they share an id and __typename, the cache will need to treat them as completely separate entities and cannot merge them.

That said, you could manually configure cache redirects: Advanced topics on caching in Apollo Client - Apollo GraphQL Docs

1 Like