React-apollo: Set network status to 3 with cache-and-network fetch policy

Created on 8 Oct 2017  路  26Comments  路  Source: apollographql/react-apollo

Intended outcome:

I want to show my users that the app is loading fresh data in the background when they get a render from the cache. (i.e. fetchPolicy is set to cache-and-network) In our app, this mostly happens when users navigate back to a page they've been on previously and we render the data from the cache first, while using cache-and-network to load fresh data from the server.

Actual outcome:

I can't do that because networkStatus does not expose that information.

Idea:

Rather than networkStatus 3 being specific to this.props.data.refetch(), why not also set the networkStatus to 3 when the data is refetched by the cache-and-network fetch policy? The data is being _refetched_ (even if not by calling refetch()) so it makes sense for the networkStatus to reflect that reality.

bug-upstream in-progress

Most helpful comment

I can also confirm that the networkStatus is always alternating between 1 and 7 when having the fetchPolicy set to cache-and-network. Is there anyway around having a loading spinner show when for a subsequent fetch? Did anyone find a solution to this?

All 26 comments

This issue has been automatically labled because it has not had recent activity. If you have not received a response from anyone, please mention the repository maintainer (most likely @jbaxleyiii). It will be closed if no further activity occurs. Thank you for your contributions to React Apollo!

Hah @stale take that, now I can label it myself! 馃枙馃槅 (thanks @jbaxleyiii)

This might've been fixed with the Apollo Client 2.0 rewrite which would be awesome, but I can't confirm that as we haven't had time to upgrade yet.

Using Apollo Client 2.0, I can confirm that networkStatus is still 1 while using cache-and-network fetch policy.

This issue has been automatically labled because it has not had recent activity. If you have not received a response from anyone, please mention the repository maintainer (most likely @jbaxleyiii). It will be closed if no further activity occurs. Thank you for your contributions to React Apollo!

I can also confirm that the networkStatus is always alternating between 1 and 7 when having the fetchPolicy set to cache-and-network. Is there anyway around having a loading spinner show when for a subsequent fetch? Did anyone find a solution to this?

I am using a workaround until this is fixed. I am querying the cache to see if I have the result cached, if that is the case I don't render the loading spinner:

<Query query={query} fetchPolicy="cache-and-network">
  {({ loading, error, data, client, variables }) => {
    const { complete } = client.cache.diff({
      query: client.cache.transformDocument(query),
      variables,
      returnPartialData: true,
      optimistic: false
    });
    if (!complete && loading) return <Loading/>;
    if (error) return <Error error={error}/>;
    return <div>Render data {data}</div>;
  }}
</Query>

+1
Please add a different networkStatus to cache-and-network when the data is in the cache.

Rendering a Loading component on networkStatus = 1 makes cache-and-network completely useless, behavior is the same as network-only...

I feel like networkStatus should equal 4 as it is essentially doing a refetch.

No news on this, right? Is there a workaround until resolution?

I have found another funny workaround for the problem:

<Query query={query} fetchPolicy="cache-and-network">
  {(networkQuery) => (
    <Query query={query}>
      {(cacheQuery) => {
        if (networkQuery.loading && ! cacheQuery.loading) return <ReLoading />;
        if (cacheQuery.loading) return <Loading />;
        if (error) return <Error error={error}/>;
        return <Data />;
    }}
    </Query>
  )}
</Query>

fetch policy can be either cache-and-network or network-only

@andrei-zhaleznichenka is this better than this: https://github.com/apollographql/react-apollo/issues/1217#issuecomment-389876741?

@mxstbr any news about this? About cache-and-network status code in networkStatus? Still nothing or did I miss some news?

+1

This was addressed in https://github.com/apollographql/apollo-client/pull/4765, and the fix is available in react-apollo 2.5.6. Thanks!

@hwillson Has anyone confirmed that this is working? I still see networkStatus: 1 all the time when the network kicks in despite complete being true.

@declanelcocks Any chance you can put together a small runnable reproduction using 2.5.6?

@hwillson A bit difficult for me to create a runnable reproduction at the moment since it's part of a large app. But anyway, if I log a few things when a cache-and-network query loads, I will get:

1. { networkStatus: 7, complete: true, loading: false }
2. { networkStatus: 1, complete: true, loading: true }
3. { networkStatus: 7, complete: true, loading: false }

I'm getting complete from this (as above):

const cache = result.client.cache.diff({
  query: result.client.cache.transformDocument(this.props.query),
  variables: this.props.variables,
  returnPartialData: true,
  optimistic: false
});

My current workaround, as I've seen in older issue threads, is to do the following:

const showCache =
  this.props.fetchPolicy !== 'network-only' &&
  this.props.fetchPolicy !== 'no-cache' &&
  cache.complete;

const loading = showCache ? false : result.loading

There's more to it, but you get the gist. I got the idea from here and also from https://github.com/apollographql/react-apollo/issues/2601 where people came to similar solutions. This is with [email protected].

Does not work for me as well. I鈥檝e created a repo reproducing the problem: https://github.com/marek-saji/react-apollo-1217 using starwars-server.

image

@hwillson Here is another minimal reproduction:

https://codesandbox.io/s/apollo-cache-network-issue-miren

Using apollo-client 2.6.4.

Seems like this is still an issue as per @kylesuss's reproduction - any news regarding this?

Using hooks:

import { useQuery } from '@apollo/react-hooks';
import gql from 'graphql-tag';

const query = gql` ... `;
const variables = { ... };

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

// Query the cache
let inCache = true;
if (loading) {
  try {
    client.readQuery({ query, variables }); // Read from cache. Error thrown if empty
  } catch {
    inCache = false;
  }
}

return (loading && !inCache) ? <Loading /> : <Data />;

Based on previous solutions/workarounds, I have made a custom hook for this situation:

// useApolloCacheQuery.ts
import { useApolloClient } from '@apollo/react-hooks'
import { OperationVariables } from 'apollo-boost'
import { Cache } from 'apollo-cache'
import { DocumentNode } from 'graphql'

/** Custom hook to query the cache to determine if query result exists already */
export default function useApolloCacheQuery<T>(
  query: DocumentNode,
  variables: OperationVariables,
): Cache.DiffResult<T> {
  const { cache } = useApolloClient()
  return cache.diff({
    query: cache.transformDocument(query),
    variables,
    returnPartialData: true,
    optimistic: false,
  })
}

// Component.tsx
// ..
const { data, loading } = useQuery<DataResponse>(query, {
  variables,
})

const { complete } = useApolloCacheQuery(query, variables)

return (!complete && loading) ? <Loader /> : <Child />;
// ..

Can we reopen this case?

Still having issues here as well ! Right now you cant really follow the stale-while-revalidate pattern, which makes cache-and-network completely useless. 馃槶

Let's reopen it, I want to use SWR too!

I wrote two custom hooks that are wrappers around useQuery and useLazyQuery and rewrite the loading property in order to enable this behavior. You can find them here: https://gist.github.com/alexvilchis/64a5b07172e8e216c6542f4f4b637cdd

They simply do what @sincospi said: check the cache and set loading to true if it didn't find an entry. I found this to be the solution with less refactoring needed.

Was this page helpful?
0 / 5 - 0 ratings