apollo-client icon indicating copy to clipboard operation
apollo-client copied to clipboard

No difference beetween `cache-and-network` and `network-only` strategies!

Open fuads96 opened this issue 4 years ago • 12 comments

I think the cache-and-network strategy doesn't work properly and acts similar to network-only.

What To Expect

  1. apollo sends two queries to cache and network in parallel.
  2. if doesn't exist in cache waiting for network and store in cache for next query.
  3. if exists, render data and wait for network in background for syncing data.

but in step 3 :

apollo doesn't render cache data Immediately until network data is received. This is not fast and behaves like network-only strategy.

fuads96 avatar Jan 22 '21 03:01 fuads96

have noticed this as well; seems like there should be another exposed boolean like refetching or something so loading isn't used when there is relevant data in the cache and the network request is running in the background

wminshew avatar Feb 02 '21 03:02 wminshew

This is the solution we are using to expose a refetching prop so we can control rendering behaviour better @wminshew @foad-salawati

import type { OperationVariables, QueryResult } from "@apollo/react-common";
import type { QueryHookOptions } from "@apollo/react-hooks";
import { useQuery as useApolloQuery } from "@apollo/react-hooks";
import type { DocumentNode } from "graphql";

export function useQuery<TData = any, TVariables = OperationVariables>(
  query: DocumentNode,
  options?: QueryHookOptions<TData, TVariables>,
): QueryResult<TData, TVariables> & {
  refetching: boolean;
} {
  const response = useApolloQuery<TData, TVariables>(query, options);
  return {
    ...response,
    refetching: response.networkStatus === 4,
  };
}

Then you can do

const { refetching } = useQuery(aQueryDocument);

I know it's not a real solution to the issue, but maybe it helps as a patch

fforres avatar Feb 11 '21 01:02 fforres

Also have this problem, cache-and-network is not loading from cache first

lassesteffen avatar Feb 22 '21 17:02 lassesteffen

@foad-salawati did you find a workaround?

lassesteffen avatar Feb 23 '21 08:02 lassesteffen

@foad-salawati did you find a workaround?

Not yet! follow this opened issue #1781 for some solutions or a new released in the future.

fuads96 avatar Feb 23 '21 09:02 fuads96

I just saw that if you use notifyOnNetworkStatusChange: true it works for me and does return the cached data on the first return

lassesteffen avatar Feb 23 '21 09:02 lassesteffen

I just saw that if you use notifyOnNetworkStatusChange: true it works for me and does return the cached data on the first return

using both notifyOnNetworkStatusChange: true and fetchPolicy: 'cache-and-network', didn't solve the issue

HoseinGhanbari avatar Nov 23 '23 06:11 HoseinGhanbari

using both notifyOnNetworkStatusChange: true and fetchPolicy: 'cache-and-network', didn't solve the issue

Neither with my setup: "@apollo/client": "^3.10.4"

llamington avatar May 18 '24 06:05 llamington

using both notifyOnNetworkStatusChange: true and fetchPolicy: 'cache-and-network', didn't solve the issue

still happening. didn't work with my setup too:

"@apollo/client": "^3.10.4",
"apollo-angular": "^7.0.1",

HoseinGhanbari avatar May 19 '24 02:05 HoseinGhanbari

This was really annoying me too, but I think I finally have a solution.

The problem is that that, even though data gets the cached value immediately, the loading state still gets set to true while the additional network request is running. And so if you're rendering a "Loading" component based on loading, then you won't see the new data.

The solution is to check both the data and the loading state before rendering your "Loading" UI.

const {data, loading, error } = useQuery ( {variables, fetchPolicy: 'cache-and-network' });

if (loading && !data) return <LoadingComponent />

return <DataComponent data={data} />

This is working for me -- I get the cached result immediately when there is one, and a Loader when there isn't any cache available (and the UI gets updated when new data comes in from the network request, as expected).

CarlosNZ avatar May 25 '24 10:05 CarlosNZ

Found a temporary solution which is simulating cache-and-network somehow, just set fetchPolicy: 'cache-first', and also do ref.refetch(); whenever a "query" gets send to the server. Actually this is not the way I like but the REAL cache-and-network is not working.

    query<T = any, V extends Record<string, any> = {}>(query: DocumentNode, variables?: V, fetchPolicy: WatchQueryFetchPolicy = 'cache-and-network'): GeneralQueryType<T, V> {
        const ref = this.apollo.watchQuery<T, V>({
            query,
            variables,
            context: this.context,
            fetchPolicy: 'cache-first',
            refetchWritePolicy: 'overwrite',
        });

        const obs = ref.valueChanges.pipe(
            filter(result => result.networkStatus === NetworkStatus.ready),
            map(response => response.data));

        // NOTICE :: temporary workaround
        ref.refetch();

        return {
            obs,
            ref
        };
    }

HoseinGhanbari avatar May 30 '24 04:05 HoseinGhanbari

Turns out apollo won't be able to cache previous results correctly depending on your query and whether it has field called id, you will need to set type policies so the query results can be properly normalised and saved in cache.

https://www.apollographql.com/docs/react/caching/cache-configuration/

This worked for me after setting those type policies, use the apollo client devtool to check your query results and see if they have been cached.

Hopefully this helps someone out there.

mink-ang avatar Jul 02 '24 08:07 mink-ang