Skip to content

Commit

Permalink
Implement ObservableQuery#isDifferentFromLastResult. (#4069)
Browse files Browse the repository at this point in the history
This commit is a more conservative version of
e66027c

We still need to make a deep clone of observableQuery.lastResult in order
to determine if future results are different (see #3992), but we can
restrict the use of that snapshot to a single method, rather than
replacing observableQuery.lastResult with the snapshot.

Should help with #4054 and #4031.
  • Loading branch information
benjamn authored Oct 30, 2018
1 parent 4ef4633 commit 905001e
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 12 deletions.
20 changes: 18 additions & 2 deletions packages/apollo-client/src/core/ObservableQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export class ObservableQuery<
private subscriptionHandles: Subscription[];

private lastResult: ApolloQueryResult<TData>;
private lastResultSnapshot: ApolloQueryResult<TData>;
private lastError: ApolloError;

constructor({
Expand Down Expand Up @@ -201,7 +202,7 @@ export class ObservableQuery<
}

const result = {
data: cloneDeep(data),
data,
loading: isNetworkRequestInFlight(networkStatus),
networkStatus,
} as ApolloQueryResult<TData>;
Expand All @@ -216,11 +217,24 @@ export class ObservableQuery<

if (!partial) {
this.lastResult = { ...result, stale: false };
this.lastResultSnapshot = cloneDeep(this.lastResult);
}

return { ...result, partial } as ApolloCurrentResult<TData>;
}

// Compares newResult to the snapshot we took of this.lastResult when it was
// first received.
public isDifferentFromLastResult(newResult: ApolloQueryResult<TData>) {
const { lastResultSnapshot: snapshot } = this;
return !(
snapshot && newResult &&
snapshot.networkStatus === newResult.networkStatus &&
snapshot.stale === newResult.stale &&
isEqual(snapshot.data, newResult.data)
);
}

// Returns the last result that observer.next was called with. This is not the same as
// currentResult! If you're not sure which you need, then you probably need currentResult.
public getLastResult(): ApolloQueryResult<TData> {
Expand All @@ -233,6 +247,7 @@ export class ObservableQuery<

public resetLastResults(): void {
delete this.lastResult;
delete this.lastResultSnapshot;
delete this.lastError;
this.isTornDown = false;
}
Expand Down Expand Up @@ -585,7 +600,8 @@ export class ObservableQuery<

const observer: Observer<ApolloQueryResult<TData>> = {
next: (result: ApolloQueryResult<TData>) => {
this.lastResult = cloneDeep(result);
this.lastResult = result;
this.lastResultSnapshot = cloneDeep(result);
this.observers.forEach(obs => obs.next && obs.next(result));
},
error: (error: ApolloError) => {
Expand Down
13 changes: 3 additions & 10 deletions packages/apollo-client/src/core/QueryManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
getQueryDefinition,
isProduction,
hasDirectives,
isEqual,
} from 'apollo-utilities';

import { QueryScheduler } from '../scheduler/scheduler';
Expand Down Expand Up @@ -605,15 +604,9 @@ export class QueryManager<TStore> {
}

if (observer.next) {
const isDifferentResult = !(
lastResult &&
resultFromStore &&
lastResult.networkStatus === resultFromStore.networkStatus &&
lastResult.stale === resultFromStore.stale &&
isEqual(lastResult.data, resultFromStore.data)
);

if (isDifferentResult || previouslyHadError) {
if (previouslyHadError ||
!observableQuery ||
observableQuery.isDifferentFromLastResult(resultFromStore)) {
try {
observer.next(resultFromStore);
} catch (e) {
Expand Down

0 comments on commit 905001e

Please sign in to comment.