-
Notifications
You must be signed in to change notification settings - Fork 786
Never fetch recycled queries on network interface #531
Changes from 7 commits
9722637
9777716
d39b3c1
82aa79f
e1bbde9
278fdce
2190a23
b6ff87f
f653cd3
b452ebe
aa6795f
c9d20c0
897f0e4
965a395
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -635,7 +635,10 @@ class ObservableQueryRecycler { | |
public recycle (observableQuery: ObservableQuery<any>): void { | ||
// Stop the query from polling when we recycle. Polling may resume when we | ||
// reuse it and call `setOptions`. | ||
observableQuery.stopPolling(); | ||
observableQuery.setOptions({ | ||
fetchPolicy: 'cache-only', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On second thought, I’m not ready to merge this because if an observable query gets reused the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the solution is to update line 672 so that it sets the default fetch policy if no other fetch policy was found. So: observableQuery.setOptions({
...options,
fetchPolicy: options.fetchPolicy || 'xyz',
}); Where There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure! const oldOptions = this.options;
this.options = {
...this.options,
...opts,
} as WatchQueryOptions; Ideally I'd like to remove both the Any ideas? I'll commit the new breaking test case for now (which is testing for strict equality of options before and after recycle). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've pushed a possible fix for reverting the options changed when recycling. IMHO it's a little on the hacky side since I need to manually overwrite the Maybe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let’s try instead saving the old options in But perhaps this isn’t the right thing to do at all. Perhaps what we really need to do is create some kind of light-weight subscribe in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The issue with merging options is that you cannot remove any - only update and add. I think But if it's a sound approach to simply override the I haven't studied the whole thing to fully reason about the recycler. However, the current issue with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Setting to I don’t like the idea of setting |
||
pollInterval: 0, | ||
}); | ||
|
||
this.observableQueries.push({ | ||
observableQuery, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,8 +5,8 @@ import * as ReactDOM from 'react-dom'; | |
import * as renderer from 'react-test-renderer'; | ||
import { mount } from 'enzyme'; | ||
import gql from 'graphql-tag'; | ||
|
||
import ApolloClient, { ApolloError } from 'apollo-client'; | ||
import { NetworkInterface } from 'apollo-client/transport/networkInterface'; | ||
import { connect } from 'react-redux'; | ||
import { withState } from 'recompose'; | ||
|
||
|
@@ -2176,6 +2176,76 @@ describe('queries', () => { | |
expect(Object.keys((client as any).queryManager.observableQueries)).toEqual(['1']); | ||
}); | ||
|
||
it('will not try to refetch recycled `ObservableQuery`s when resetting the client store', () => { | ||
const query = gql`query people { allPeople(first: 1) { people { name } } }`; | ||
const data = { allPeople: { people: [ { name: 'Luke Skywalker' } ] } }; | ||
const networkInterface = { | ||
query: jest.fn(), | ||
} as NetworkInterface; | ||
const client = new ApolloClient({ networkInterface, addTypename: false }); | ||
|
||
@graphql(query) | ||
class Container extends React.Component<any, any> { | ||
render () { | ||
return null; | ||
} | ||
} | ||
|
||
const wrapper1 = renderer.create( | ||
<ApolloProvider client={client}> | ||
<Container/> | ||
</ApolloProvider> | ||
); | ||
|
||
expect(Object.keys((client as any).queryManager.observableQueries)).toEqual(['1']); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we check that this observable query still exists after we unmount as well? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed |
||
const queryObservable1 = (client as any).queryManager.observableQueries['1'].observableQuery; | ||
|
||
// The query should only have been invoked when first mounting and not when resetting store | ||
expect(networkInterface.query).toHaveBeenCalledTimes(1); | ||
|
||
wrapper1.unmount(); | ||
|
||
expect(Object.keys((client as any).queryManager.observableQueries)).toEqual(['1']); | ||
const queryObservable2 = (client as any).queryManager.observableQueries['1'].observableQuery; | ||
|
||
expect(queryObservable1).toBe(queryObservable2); | ||
|
||
client.resetStore(); | ||
|
||
// The query should not have been fetch again | ||
expect(networkInterface.query).toHaveBeenCalledTimes(1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let’s also check that this method was called once before we unmounted. You should also duplicate this test and assert that query is called twice if we do not unmount, but we still call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed |
||
}); | ||
|
||
it('will refetch active `ObservableQuery`s when resetting the client store', () => { | ||
const query = gql`query people { allPeople(first: 1) { people { name } } }`; | ||
const data = { allPeople: { people: [ { name: 'Luke Skywalker' } ] } }; | ||
const networkInterface = { | ||
query: jest.fn(), | ||
} as NetworkInterface; | ||
const client = new ApolloClient({ networkInterface, addTypename: false }); | ||
|
||
@graphql(query) | ||
class Container extends React.Component<any, any> { | ||
render () { | ||
return null; | ||
} | ||
} | ||
|
||
const wrapper1 = renderer.create( | ||
<ApolloProvider client={client}> | ||
<Container/> | ||
</ApolloProvider> | ||
); | ||
|
||
expect(Object.keys((client as any).queryManager.observableQueries)).toEqual(['1']); | ||
|
||
expect(networkInterface.query).toHaveBeenCalledTimes(1); | ||
|
||
client.resetStore(); | ||
|
||
expect(networkInterface.query).toHaveBeenCalledTimes(2); | ||
}); | ||
|
||
it('will recycle `ObservableQuery`s when re-rendering a portion of the tree', done => { | ||
const query = gql`query people { allPeople(first: 1) { people { name } } }`; | ||
const data = { allPeople: { people: [ { name: 'Luke Skywalker' } ] } }; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let’s remove
stopPolling
forpollInterval: 0
insetOptions
. It does the same thing: https://github.com/apollographql/apollo-client/blob/1e986c57e12d98f2831616005ef0211d4c9689d1/src/core/ObservableQuery.ts#L307-L311There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed