Skip to content

Commit

Permalink
Merge branch 'main' into issue-11184/race-condition-bug
Browse files Browse the repository at this point in the history
  • Loading branch information
jerelmiller authored Aug 31, 2023
2 parents 7c173a2 + 51045c3 commit 9b32cbb
Show file tree
Hide file tree
Showing 14 changed files with 434 additions and 74 deletions.
5 changes: 5 additions & 0 deletions .changeset/angry-llamas-walk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@apollo/client": patch
---

Fixes race conditions in useReactiveVar that may prevent updates to the reactive variable from propagating through the hook.
6 changes: 6 additions & 0 deletions .changeset/nine-balloons-compete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@apollo/client": patch
---

Adds a new devtools registration mechanism and tweaks the mechanism behind the
"devtools not found" mechanic.
5 changes: 5 additions & 0 deletions .changeset/wise-clouds-approve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@apollo/client": patch
---

Fixes an issue where refetching from `useBackgroundQuery` via `refetch` with an error after an error was already fetched would get stuck in a loading state.
4 changes: 2 additions & 2 deletions .size-limit.cjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const checks = [
{
path: "dist/apollo-client.min.cjs",
limit: "38074",
limit: "38190",
},
{
path: "dist/main.cjs",
Expand All @@ -10,7 +10,7 @@ const checks = [
{
path: "dist/index.js",
import: "{ ApolloClient, InMemoryCache, HttpLink }",
limit: "31980",
limit: "32044",
},
...[
"ApolloProvider",
Expand Down
20 changes: 10 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@
"ts-jest": "29.1.1",
"ts-jest-resolver": "2.0.1",
"ts-node": "10.9.1",
"typedoc": "0.24.7",
"typedoc": "0.25.0",
"typescript": "5.2.2",
"wait-for-observables": "1.0.3",
"web-streams-polyfill": "3.2.1",
Expand Down
66 changes: 40 additions & 26 deletions src/core/ApolloClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,41 +187,55 @@ export class ApolloClient<TCacheShape> implements DataProxy {
this.reFetchObservableQueries = this.reFetchObservableQueries.bind(this);

if (connectToDevTools && typeof window === "object") {
(window as any).__APOLLO_CLIENT__ = this;
type DevToolsConnector = {
push(client: ApolloClient<any>): void;
};
const windowWithDevTools = window as Window & {
[devtoolsSymbol]?: DevToolsConnector;
__APOLLO_CLIENT__?: ApolloClient<any>;
};
const devtoolsSymbol = Symbol.for("apollo.devtools");
(windowWithDevTools[devtoolsSymbol] =
windowWithDevTools[devtoolsSymbol] || ([] as DevToolsConnector)).push(
this
);
windowWithDevTools.__APOLLO_CLIENT__ = this;
}

/**
* Suggest installing the devtools for developers who don't have them
*/
if (!hasSuggestedDevtools && connectToDevTools && __DEV__) {
hasSuggestedDevtools = true;
if (
typeof window !== "undefined" &&
window.document &&
window.top === window.self &&
!(window as any).__APOLLO_DEVTOOLS_GLOBAL_HOOK__
) {
const nav = window.navigator;
const ua = nav && nav.userAgent;
let url: string | undefined;
if (typeof ua === "string") {
if (ua.indexOf("Chrome/") > -1) {
url =
"https://chrome.google.com/webstore/detail/" +
"apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm";
} else if (ua.indexOf("Firefox/") > -1) {
url =
"https://addons.mozilla.org/en-US/firefox/addon/apollo-developer-tools/";
setTimeout(() => {
if (
typeof window !== "undefined" &&
window.document &&
window.top === window.self &&
!(window as any).__APOLLO_DEVTOOLS_GLOBAL_HOOK__
) {
const nav = window.navigator;
const ua = nav && nav.userAgent;
let url: string | undefined;
if (typeof ua === "string") {
if (ua.indexOf("Chrome/") > -1) {
url =
"https://chrome.google.com/webstore/detail/" +
"apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm";
} else if (ua.indexOf("Firefox/") > -1) {
url =
"https://addons.mozilla.org/en-US/firefox/addon/apollo-developer-tools/";
}
}
if (url) {
invariant.log(
"Download the Apollo DevTools for a better development " +
"experience: %s",
url
);
}
}
if (url) {
invariant.log(
"Download the Apollo DevTools for a better development " +
"experience: %s",
url
);
}
}
}, 10000);
}

this.version = version;
Expand Down
26 changes: 26 additions & 0 deletions src/core/ObservableQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,32 @@ Did you mean to call refetch(variables) instead of refetch({ variables })?`,
return this.reobserveAsConcast(newOptions, newNetworkStatus).promise;
}

public resubscribeAfterError(
onNext: (value: ApolloQueryResult<TData>) => void,
onError?: (error: any) => void,
onComplete?: () => void
): ObservableSubscription;

public resubscribeAfterError(
observer: Observer<ApolloQueryResult<TData>>
): ObservableSubscription;

public resubscribeAfterError(...args: [any, any?, any?]) {
// If `lastError` is set in the current when the subscription is re-created,
// the subscription will immediately receive the error, which will
// cause it to terminate again. To avoid this, we first clear
// the last error/result from the `observableQuery` before re-starting
// the subscription, and restore the last value afterwards so that the
// subscription has a chance to stay open.
const last = this.last;
this.resetLastResults();

const subscription = this.subscribe(...args);
this.last = last;

return subscription;
}

// (Re)deliver the current result to this.observers without applying fetch
// policies or making network requests.
private observe() {
Expand Down
6 changes: 6 additions & 0 deletions src/react/cache/QueryReference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,12 @@ export class InternalQueryReference<TData = unknown> {
}

private handleError(error: ApolloError) {
this.subscription.unsubscribe();
this.subscription = this.observable.resubscribeAfterError(
this.handleNext,
this.handleError
);

switch (this.status) {
case "loading": {
this.status = "idle";
Expand Down
Loading

0 comments on commit 9b32cbb

Please sign in to comment.