-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid making network requests when skip is true #6752
Changes from all commits
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 |
---|---|---|
|
@@ -227,6 +227,8 @@ export class QueryData<TData, TVariables> extends OperationData { | |
} | ||
|
||
private updateObservableQuery() { | ||
if (this.getOptions().skip) return; | ||
|
||
// If we skipped initially, we may not have yet created the observable | ||
if (!this.currentObservable) { | ||
this.initializeObservableQuery(); | ||
|
@@ -326,6 +328,13 @@ export class QueryData<TData, TVariables> extends OperationData { | |
// When skipping a query (ie. we're not querying for data but still want | ||
// to render children), make sure the `data` is cleared out and | ||
// `loading` is set to `false` (since we aren't loading anything). | ||
// | ||
// NOTE: We no longer think this is the correct behavior. Skipping should | ||
// not automatically set `data` to `undefined`, but instead leave the | ||
// previous data in place. In other words, skipping should not mandate | ||
// that previously received data is all of a sudden removed. Unfortunately, | ||
// changing this is breaking, so we'll have to wait until Apollo Client | ||
// 4.0 to address this. | ||
Comment on lines
+332
to
+337
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. +1 |
||
if (options.skip) { | ||
result = { | ||
...result, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -596,11 +596,16 @@ describe('[queries] skip', () => { | |
ranQuery++; | ||
return f ? f(o) : null; | ||
}).concat( | ||
mockSingleLink({ | ||
request: { query }, | ||
result: { data }, | ||
newData: () => ({ data: nextData }) | ||
}) | ||
mockSingleLink( | ||
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. This test was behaving flakily due to its use of |
||
{ | ||
request: { query }, | ||
result: { data }, | ||
}, | ||
{ | ||
request: { query }, | ||
result: { data: nextData }, | ||
}, | ||
) | ||
); | ||
|
||
const client = new ApolloClient({ | ||
|
@@ -626,26 +631,46 @@ describe('[queries] skip', () => { | |
expect(ranQuery).toBe(1); | ||
break; | ||
case 2: | ||
// The first batch of data is fetched over the network, and | ||
// verified here, followed by telling the component we want to | ||
// skip running subsequent queries. | ||
expect(this.props.data.loading).toBe(false); | ||
expect(this.props.data.allPeople).toEqual(data.allPeople); | ||
expect(ranQuery).toBe(1); | ||
setTimeout(() => { | ||
this.props.setSkip(true); | ||
}); | ||
break; | ||
case 3: | ||
// This render is triggered after setting skip to true. Now | ||
// let's set skip to false to re-trigger the query. | ||
expect(this.props.data).toBeUndefined(); | ||
expect(ranQuery).toBe(1); | ||
setTimeout(() => { | ||
this.props.setSkip(false); | ||
}); | ||
break; | ||
case 4: | ||
expect(this.props.data!.loading).toBe(true); | ||
expect(ranQuery).toBe(3); | ||
// Since the `nextFetchPolicy` was set to `cache-first`, our | ||
// query isn't loading as it's able to find the result of the | ||
// query directly from the cache. Let's trigger a refetch | ||
// to manually load the next batch of data. | ||
expect(this.props.data!.loading).toBe(false); | ||
expect(this.props.data.allPeople).toEqual(data.allPeople); | ||
expect(ranQuery).toBe(1); | ||
setTimeout(() => { | ||
this.props.data.refetch(); | ||
}); | ||
break; | ||
case 5: | ||
expect(this.props.data!.loading).toBe(true); | ||
expect(ranQuery).toBe(2); | ||
break; | ||
case 6: | ||
// The next batch of data has loaded. | ||
expect(this.props.data!.loading).toBe(false); | ||
expect(ranQuery).toBe(3); | ||
expect(this.props.data.allPeople).toEqual(nextData.allPeople); | ||
expect(ranQuery).toBe(2); | ||
break; | ||
default: | ||
} | ||
|
@@ -673,7 +698,7 @@ describe('[queries] skip', () => { | |
); | ||
|
||
await wait(() => { | ||
expect(count).toEqual(5); | ||
expect(count).toEqual(6); | ||
}); | ||
}); | ||
|
||
|
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.
Currently, when the first option starts with skip: true, there is a problem that refetch is not ready and cannot be executed. How about changing the order as follows?
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.
Not that this isn't a bug, but isn't an initial state with skip: true what lazy query is for?
ie
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.
Since there is no clear guidance on this in the official documents, a lot of users will think and use just like me. It is not easy to think of 'skip' affecting 'refetch' without any explanation.
And I can do it as you explained, but it has already become a strangely shaped code. And useLazyQuery's refetch function returns void, so we need to add more useEffect to use the response. The return value of useQuery's refetch is a promise, so you can use data directly with async/await. It's confusing why it was designed this way, but not all of these relationships seem clear and consistent.
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.
I just had exactly the same issue as you @gtolarc and was also using
useQuery
to getrefetch
becauseuseLazyQuery
returns void instead of a promise.I'd be in favor of init the observable as well, as this change is quite breaking for a lot of people I guess 😕