Skip to content

Commit

Permalink
Go back to associating Apollo context with React.createContext.
Browse files Browse the repository at this point in the history
Should fix #8790, by allowing multiple copies of `@apollo/client`
(uncommon) to share the same `React.createContext[contextKey]` object.
  • Loading branch information
benjamn committed Sep 16, 2021
1 parent 469f995 commit b9c3f0a
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 14 deletions.
1 change: 1 addition & 0 deletions src/__tests__/__snapshots__/exports.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ Array [
"argumentsObjectFromField",
"asyncMap",
"buildQueryFromSelectionSet",
"canUseSymbol",
"canUseWeakMap",
"canUseWeakSet",
"checkDocument",
Expand Down
27 changes: 14 additions & 13 deletions src/react/context/ApolloContext.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
import * as React from 'react';
import { ApolloClient } from '../../core';
import { canUseWeakMap } from '../../utilities';
import { canUseSymbol } from '../../utilities';
import type { RenderPromises } from '../ssr';

export interface ApolloContextValue {
client?: ApolloClient<object>;
renderPromises?: Record<any, any>;
renderPromises?: RenderPromises;
}

// To make sure Apollo Client doesn't create more than one React context
// (which can lead to problems like having an Apollo Client instance added
// in one context, then attempting to retrieve it from another different
// context), a single Apollo context is created and tracked in global state.
// We use React.createContext as the key instead of just React to avoid
// ambiguities between default and namespace React imports.
const contextKey = canUseSymbol
? Symbol.for('__APOLLO_CONTEXT__')
: '__APOLLO_CONTEXT__';

const cache = new (canUseWeakMap ? WeakMap : Map)<
typeof React.createContext,
React.Context<ApolloContextValue>
>();

export function getApolloContext() {
let context = cache.get(React.createContext)!;
export function getApolloContext(): React.Context<ApolloContextValue> {
let context = (React.createContext as any)[contextKey] as React.Context<ApolloContextValue>;
if (!context) {
context = React.createContext<ApolloContextValue>({});
Object.defineProperty(React.createContext, contextKey, {
value: context = React.createContext<ApolloContextValue>({}),
enumerable: false,
writable: false,
configurable: true,
});
context.displayName = 'ApolloContext';
cache.set(React.createContext, context);
}
return context;
}
Expand Down
4 changes: 4 additions & 0 deletions src/utilities/common/canUse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ export const canUseWeakMap = typeof WeakMap === 'function' && !(
);

export const canUseWeakSet = typeof WeakSet === 'function';

export const canUseSymbol =
typeof Symbol === 'function' &&
typeof Symbol.for === 'function';
3 changes: 2 additions & 1 deletion src/utilities/observables/subclassing.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Observable } from "./Observable";
import { canUseSymbol } from "..";

// Generic implementations of Observable.prototype methods like map and
// filter need to know how to create a new Observable from an Observable
Expand All @@ -17,7 +18,7 @@ export function fixObservableSubclass<
// can't assign to it with a normal assignment expression.
Object.defineProperty(subclass, key, { value: Observable });
}
if (typeof Symbol === "function" && Symbol.species) {
if (canUseSymbol && Symbol.species) {
set(Symbol.species);
}
// The "@@species" string is used as a fake Symbol.species value in some
Expand Down

0 comments on commit b9c3f0a

Please sign in to comment.