Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

FetchPolicy 'network-only' returns cached value #556

Closed
davidye opened this issue Mar 22, 2017 · 129 comments
Closed

FetchPolicy 'network-only' returns cached value #556

davidye opened this issue Mar 22, 2017 · 129 comments
Assignees
Labels
has-reproduction ❤ Has a reproduction in a codesandbox or single minimal repository

Comments

@davidye
Copy link
Contributor

davidye commented Mar 22, 2017

Steps to Reproduce

Not sure if this is an issue with react-apollo or apollo-client.

  1. Create graphql() component with fetchPolicy: 'network-only'
  2. Render the component once - data is fetched from server
  3. Print out this.props.data
  4. Update the underlying query data
  5. Render the component again - this.props.data is stale

Buggy Behavior

When using fetchPolicy: 'network-only', Component receives the previously cached value.

Expected Behavior

When using fetchPolicy: 'network-only' should only return fresh results from server.

Version

  • apollo-client@1.0.0-rc.6
  • react-apollo@1.0.0-rc.3
@helfer
Copy link
Contributor

helfer commented Mar 22, 2017

Thanks @davidye, this sounds like a bug. Could you provide a reproduction with https://github.com/apollographql/react-apollo-error-template? That would help us figure out what's going on.

@irfanlone
Copy link

I am also seeing the same issue, fetchPolicy: 'network-only', Component receives the previously cached value. versions apollo-client@1.0.0-rc.3 react-apollo@1.0.0-rc.3. I will try to reproduce it.

irfanlone pushed a commit to irfanlone/react-apollo-error-template that referenced this issue Mar 24, 2017
@helfer
Copy link
Contributor

helfer commented Mar 24, 2017

Thanks @irfanlone that would be great! Let me know if you need any help with it 🙂

@irfanlone
Copy link

@helfer, Here is the PR reproducing the issue, apollographql/react-apollo-error-template#2. Let me know if it makes sense. Thanks for looking into it. 🙂

@helfer
Copy link
Contributor

helfer commented Mar 24, 2017

Thanks @irfanlone. Based on your reproduction it looks like this runs two separate queries. What I'm not sure yet is how the code path is different from the one taken in this test here: https://github.com/apollographql/apollo-client/blob/master/test/client.ts#L1282

@helfer
Copy link
Contributor

helfer commented Mar 24, 2017

@irfanlone this is embarrassing, but I figured out what's wrong: The error was actually in our docs, which did not specify the right way to pass the option. In react-apollo you have to pass those options that apply to Apollo Client wrapped inside the options param:

export default graphql(
  gql`{
    food {
      id
      name
    }
  }`,
  {
    options: { fetchPolicy: 'network-only' },
  }
)(Food)

I've fixed it in the docs with this commit: https://github.com/apollographql/react-docs/commit/dd23b58303b6c8415d307b1c48e5ffbec2d45cfc

@davidye I think you most likely had the same problem, so I'll close the issue here. If this doesn't fix your issue, please re-open it.

@helfer helfer closed this as completed Mar 24, 2017
@irfanlone
Copy link

@helfer, I am sorry I actually didn't give you the right reproduction, I was already including fetchPolicy wrapped under options in my code. Right now I can't reproduce the bug on react-apollo-error-template repo but will update if i can reproduce it. Thanks.

@chompomonim
Copy link

chompomonim commented Apr 13, 2017

We're facing similar problem. Second render of component is rendering from cache.

graphql(query, {
  options: ({id, progress}) => ({
    variables: {id, progress},
    fetchPolicy: 'network-only'
  })
})(MyComponent)

react-apollo@1.0.1

@chompomonim
Copy link

@helfer I'll try to create repo with reproduction of this bug. Could you meanwhile reopen this issue?

@chompomonim
Copy link

chompomonim commented Apr 13, 2017

I just made some changes to apollo error template to reproduce this bug.

https://github.com/chompomonim/react-apollo-error-template/commit/f99ddb66f881775de2c79eda3ebddc63b9cd9a00

I'm expecting, that last member of list will change on 'refresh' button click, but it's not. Loading data from cache (even fetchPolicy: 'network-only') :/
When I'm adding pollInterval: 1000, then everything is as expected, every second time last person in the list is changing.

@chompomonim
Copy link

chompomonim commented Apr 13, 2017

After looking one more time on my example I feel, that the problem is that apollo is doing queries only when graphql() created component is mounting not every time when it's parent tries to render the Component. Any ideas how to solve this?

@helfer @stubailo

@helfer helfer reopened this Apr 13, 2017
@helfer
Copy link
Contributor

helfer commented Apr 13, 2017

@chompomonim this may be something that has to be changed in react-apollo. It's possible that react-apollo actually looked at the old forceFetch option, but doesn't look at the fetchPolicy.

@jbaxleyiii jbaxleyiii self-assigned this May 3, 2017
@stale stale bot added the wontfix label Jul 5, 2017
@Aetherall
Copy link

Same behavior here,
I can see 2 'APOLLO_QUERY_INIT' actions in reduxDevTools
First one with fetchPolicy = 'network-only'
Then an other one with the same id (so it overwrites the first one) with fetchPolicy = 'cache-first'

@Aetherall
Copy link

@davidsims9t
Copy link

@Aetherall do you know how to fix this?

@HammerSpb
Copy link

I have the same issue: apollo is doing queries only when graphql() created component!

@salujaharkirat
Copy link

Please check if options is passed as functions. I was facing issue with
"options": {"fetchPolicy": "network-only"}.

When i changed it to following it works fine.
"options": () => ({"fetchPolicy": "network-only"})

@Aetherall
Copy link

@davidsims9t My workaround was to use "cache-and-network",
and to treat the data only when ( props.data.loading === false )

I would try @jinxac 's solution first

@stale
Copy link

stale bot commented Aug 26, 2017

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!

@Panoplos
Copy link

Panoplos commented Sep 5, 2017

I was facing the same issue, here, but realised that I had a recompose branch on the HOC and failed to set the policy for both branches, just in case someone else happens to miss the obvious like I did... Haha.

@stale stale bot removed the no-recent-activity label Sep 5, 2017
@wrod7
Copy link

wrod7 commented Mar 1, 2019

fetchPolicy="network-only" still broken in the query component. (@2.5.1)
... unless im miss understanding what network-only means

are there any work arounds?

@MaxwellGover
Copy link

MaxwellGover commented Mar 1, 2019

@wrod7 You could try doing something like this under defaultOptions

const client = new ApolloClient({
      link: createHttpLink({
        uri: `//${apiDomain}/graphql`,
        fetch: customFetch,
      }),
      cache,
      link: ApolloLink.from([
        stateLink,
        createHttpLink({ uri: `//${apiDomain}/graphql`, fetch: customFetch }),
      ]),
      cache,
      defaultOptions: {
        watchQuery: {
           fetchPolicy: 'network-only',
           errorPolicy: 'ignore',
        },
        query: {
           fetchPolicy: 'network-only',
           errorPolicy: 'all',
        },
      },
    });

@pcorey
Copy link

pcorey commented Mar 1, 2019

Disregard! I was on an old version of apollo-client. Bumping apollo-boost to 0.3.1 brought my apollo-client version to 2.5.1, and everything seems to be working:

Showing...
ShowHide.js:19 Re-rendering query:
ShowHide.js:41 data received from Query: undefined {}
ShowHide.js:41 data received from Query: undefined {}
ShowHide.js:41 data received from Query: 0.6603918391040067 {random: {…}}

🎉

@wrod7
Copy link

wrod7 commented Mar 1, 2019

can you share you query component? are you using 'network-only' ? @pcorey

the default options on the apollo client didnt work for me

@pcorey
Copy link

pcorey commented Mar 1, 2019

@wrod7 The query is in the reproduction repo. Check it out.. It seems to work as I'd expect with apollo-client@2.5.1 and react-apollo@2.5.1.

@wrod7
Copy link

wrod7 commented Mar 2, 2019

still happening to me on 2.5.1

mar-02-2019 00-14-51

<Query<MeQuery, MeVariables> query={MeDocument} fetchPolicy='network-only'>
  {({ data, loading, error }) => {
    if (loading) return <div>loading</div>
    if (error || !data || (data && !data.me)) return <Redirect to='/login' />

    console.log(data)
    return (
       ...
    )
  }}
</Query>

@Greenhv
Copy link

Greenhv commented Mar 3, 2019

Hi guys, I hope you can help me with this, I'm not sure about this behavior and it might be related to this bug.

I try react-apollo@2.5.1 and apollo-client@2.5.1 in the reproduction repo and the query launches after an update as expected 🎉

Then I add react-router@4.3.1 and do some modifications to the code in the repo

ShowHide.js

export default class extends React.Component {
  render() {
    console.log("Re-rendering query:");

    return (
      <div>
        <BrowserRouter>
          <Route to="/" render={props => <Content {...props} />} />
          <br />
          <Link to="/test">Test</Link> <br />
          <Link to="/dashboard">Dashboard</Link> <br />
          <Link to="/home">Home</Link> <br />
          <Link to="/list">List</Link> <br />
        </BrowserRouter>
      </div>
    )
  }
}

Content.js

class Content extends Component {
  render() {
    const { data } = this.props;

    console.log(
      "data received from Query:",
      _.get(data, "random.value"),
      data
    );
    return (
      <div>
        <h1>Open your console!</h1>
        <p>
          The Query component eventually settled on the above value, which comes
          from the network. Click "Hide" to remove the Query component from the
          virtual DOM.
        </p>
        <p>{_.get(data, "random.value")}</p>
        {/* <p>Math.random: {Math.random()}</p> */}
        <Switch>
          <Route path="/test" render={() => <div>test</div>} />
          <Route path="/dashboard" render={() => <div>dashboard</div>} />
          <Route path="/home" render={() => <div>home</div>} />
          <Route path="/list" render={() => <div>list</div>} />
        </Switch>
      </div>
    )
  }
}

export default graphql(gql`
{
  random {
    id
    value
  }
}`, {
    options: {
      fetchPolicy: 'network-only'
    }
  })(Content);

And as you can see here, the component re-renders, but the query doesn't fire again
screen recording 2019-03-02 at 10 38 34 pm

@mieszko4
Copy link

mieszko4 commented Mar 7, 2019

I've managed to overcome this issue by passing a timestamp to variables

await apolloClient.query({
  query: getStatesCitiesQuery,
  variables: {
    antiCache: +(new Date()), // timestamp HACK
    state,
    city,
  },
});

antiCache field will force apollo to make request again and can be any name as it is ignored.

I thought that maybe my graphql server returns some Caching headers but it does not.

Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Timezone, Authorization, Platform
Access-Control-Allow-Methods: DELETE, GET, HEAD, POST, PUT, OPTIONS, TRACE
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 1556
Content-Type: application/json
Date: Thu, 07 Mar 2019 00:12:59 GMT
Server: nginx/1.14.1
X-Powered-By: Express

honesly I am not sure what the source of this issue is.

Update
I've managed to resolve my issue without this hack by explicitly calling refetch().
My issue was that I was doing setState() when I wanted to refetch but the state was resulting with the same variables so apollo did not do query. With explicit call of refetch() apollo does indeed make another request from the server.

@wrod7
Copy link

wrod7 commented Mar 18, 2019

@mieszko4 where are you calling refetch? can you show an example?

@mieszko4
Copy link

mieszko4 commented Mar 19, 2019

Sure.
I use react-native to implement virtual scroll (in <List> using <FlatList>.
So when I scroll down my from changes but when I want to refresh (pull down or coming back to this screen) I need to either call refetch to force rerunning query - if I haven't scrolled yet and my from is the same or setState - if I have scrolled and my from differs.

class ListContainer extends Component {
  cachedClasses = []
  hasReachedEnd = false
  loadingMore = false

  state = {
    from: moment(),
  }

  onLoadMore = () => {
    const { from } = this.state;

    if (!this.hasReachedEnd) {
      this.loadingMore = true;
      this.setState({
        from: from.clone()
          .add(7, 'days')
          .add(1, 'day'), // another date on subsequent request
      });
    }
  }

  render() {
    const { from } = this.state;

    return (
      <Query
        query={ListOfClassesQuery}
        fetchPolicy="network-only"
        notifyOnNetworkStatusChange
        variables={{
          from: from.format(dateApiFormat), //DATE ONLY
          until: from.clone().add(7, 'days').format(dateApiFormat), // DATE ONLY
        }}
      >
        {({
          loading, data, error, refetch,
        }) => {
          if (error) {
            return <ErrorMessage>{error}</ErrorMessage>;
          }

          if (!loading) {
            this.loadingMore = false;
            if (data.allClasses.edges.length === 0) {
              this.hasReachedEnd = true;
            } else {
              this.cachedClasses = [...this.cachedClasses, ...data.allClasses.edges];
            }
          }

          return (
            <List
              loading={loading}
              loadingMore={this.loadingMore}
              refetch={() => { // refreshes the list - called when pulling down or coming to this screen 
                this.cachedClasses = [];
                this.hasReachedEnd = false;

                const now = moment();
                // THIS FOLLOWING WAS CRITICAL TO ME ----> 
                const willVariableChange = from.format(dateApiFormat) !== now.format(dateApiFormat);
                if (willVariableChange) {
                  // apollo will refresh data on setState only if variables change
                  this.setState({
                    from: now,
                  });
                } else {
                  // otherwise wee need to force the refresh
                  // I do not wanted to use setState and refetch at the same time
                  // because it would then run query twice on some occasions
                  refetch();
                }
              }}
              allClasses={this.cachedClasses}
              onLoadMore={this.onLoadMore}
            />
          );
        }}
      </Query>
    );
  }
}

@Hatko
Copy link

Hatko commented Apr 8, 2019

Have the same issue using

"apollo-boost": "0.3.1",
"apollo-client": "2.5.1",

@martinsik
Copy link

I was having exactly the same issue. Using no-cache instead of network-only worked for me.

@andfs
Copy link

andfs commented Apr 16, 2019

Neither no-cacho or network-only works for me

mimecuvalo added a commit to mimecuvalo/helloworld that referenced this issue May 9, 2019
@yagoazedias
Copy link

@joe-askattest I had issues with client.query also. I solved it by chanaging:

  const { data: { getUser } } = await client.query({
        query: gql(queries.getUser)
      }, {
        options: {
          fetchPolicy: 'network-only'
        }
      });

to

const { data: { getUser } } = await client.query({
    query: gql(queries.getUser),
    fetchPolicy: 'network-only'
});

When you call client.query({}), the options object in the picture below represents what's passed when the request is made. It looks for options.fetchPolicy instead of options.options.fetchPolicy

screen shot 2019-01-27 at 12 48 36 pm

Yours would be

let res = await this.props.client.query({
  query: MY_QUERY,
  variables: {
    filters: this.state.arrayOfFilters,
  },
   fetchPolicy: 'network-only' 
});

Just worked to me

@hwillson
Copy link
Member

This issue has definitely gotten a bit unwieldy. Some people are reporting this issue as fixed, others as not fixed, others are reporting new issues, etc. I'm going to close this issue, but please consider opening a new issue if you're still encountering any problems. Thanks!

@damiangreen
Copy link

It's still broken!

@william-bratches
Copy link

william-bratches commented Jul 23, 2019

Still broken, and graphql's aggressive caching in general is the source of tons of bugs. Unnecessary premature optimization when you're just trying to get a simple cyclic state refresher working.

@andfs
Copy link

andfs commented Jul 24, 2019

All my errors have gone when I put errorPolicy: "all"

@HashCode55
Copy link

HashCode55 commented Sep 9, 2019

@Aetherall

If you already have the data in cache, it yields false->true->false. How did you solve this issue?

@huevoncito
Copy link

@mieszko4 antiCache solution fixed it for me. Definitely a hack. But it works.

@stearm
Copy link

stearm commented Oct 23, 2019

with new version of apollo, using hooks, it works fine for me!

@JSONRice
Copy link

JSONRice commented Nov 4, 2019

Tried it with hooks and I'm still getting the cached data when the fetchPolicy is set to "network-only" I realize "no-cache" isn't efficient (new fetch per request) but turning the cache off definitely turned it off:

  const {
    loading,
    error,
    data
  } = useQuery(LCRF_SUBCATEGORIES, {
    variables: { input: { orgId: unit.orgId, isUnitManaged: true, type: "BUDGET" } },
    fetchPolicy: "no-cache", // network-only introduces a weird defect where permissions are being cached: 107847
    notifyOnNetworkStatusChange: true,
    onError: handleGqlNetworkError,
    onCompleted: data => {
      if (data && Object.keys(data).length > 0) {
        updateLcrfSubcategoriesCopy(
          data.lcrfSubcategories.sort((row1, row2) => (row1.subcategorySortOrder > row2.subcategorySortOrder ? 1 : -1))
        );
      } else {
        console.error('LCRF_SUBCATEGORIES query returned an empty data set');
      }
    }
  });

@Falieson
Copy link

With
"@apollo/react-hooks": "3.0.0",

I make a useQuery request in one component, and then another makes a useQuery request, whichever resolves last then becomes the value of the other component. They are different queries!

my client is configured for "network-only", adding "no-cache" option to useQuery fixed the issue.

@mayuratstoreapps
Copy link

@Aetherall

If you already have the data in cache, it yields false->true->false. How did you solve this issue?

Hey, were you able to get this issue resolved?

@noumanniazi
Copy link

noumanniazi commented Jan 15, 2020

I am facing this issue in Query Component. ssr doesn't work, no-cache doesn't work. I cant add that timestamp as backend isn't in my control.

Facing issue in v2.5.8 and I have also tried updating to v3.1.3

Has this been fixed for Query Component?

Setting a pollInterval does send a new network request. But changing variables doesn't.

@noumanniazi
Copy link

How we end up fixing this is by passing refetch back and after state has updated we call the refetch to forcefully send a network call and as the input has already been updated it sends updated query params in the network call.

Not the best solution but thats how we end up solving it without cache buster. Other solutions discussed above didn't work and i didn't try useQuery(looking from the answers seemed like people ran into issues in that as well).

@jbesraa
Copy link

jbesraa commented Jan 31, 2020

This works for me
const { data, loading } = useQuery(QUERY, { fetchPolicy: 'network-only', variables: { requestVariables }, });
with
"apollo-client": "^2.6.4"

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
has-reproduction ❤ Has a reproduction in a codesandbox or single minimal repository
Projects
None yet
Development

No branches or pull requests