Skip to content

Commit 0ba17aa

Browse files
alexkirsztrojanowski
authored andcommitted
feat(useQuery, useMutation): accept client option (#95)
1 parent e8d8a9a commit 0ba17aa

File tree

5 files changed

+94
-23
lines changed

5 files changed

+94
-23
lines changed

src/ApolloContext.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,18 @@ export function ApolloProvider<TCacheShape = any>({
1919
);
2020
}
2121

22-
export function useApolloClient<TCache = object>(): ApolloClient<TCache> {
22+
export function useApolloClient<TCache = object>(
23+
overrideClient?: ApolloClient<TCache>
24+
): ApolloClient<TCache> {
2325
const client = useContext(ApolloContext);
2426

27+
// Ensures that the number of hooks called from one render to another remains
28+
// constant, despite the Apollo client read from context being swapped for
29+
// one passed directly as prop.
30+
if (overrideClient) {
31+
return overrideClient;
32+
}
33+
2534
if (!client) {
2635
// https://github.com/apollographql/react-apollo/blob/5cb63b3625ce5e4a3d3e4ba132eaec2a38ef5d90/src/component-utils.tsx#L19-L22
2736
throw new Error(

src/__tests__/useQuery-test.tsx

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -130,21 +130,25 @@ function Tasks({ query, ...options }: TasksProps) {
130130
}
131131

132132
interface TasksWrapperProps extends TasksProps {
133-
client: ApolloClient<object>;
133+
client?: ApolloClient<object>;
134134
}
135135

136136
const SuspenseCompat = ({ children }: SuspenseProps) => <>{children}</>;
137137

138138
function TasksWrapper({ client, ...props }: TasksWrapperProps) {
139139
const SuspenseComponent = props.suspend !== false ? Suspense : SuspenseCompat;
140140

141-
return (
142-
<ApolloProvider client={client}>
143-
<SuspenseComponent fallback={<>Loading with suspense</>}>
144-
<Tasks {...props} />
145-
</SuspenseComponent>
146-
</ApolloProvider>
141+
const inner = (
142+
<SuspenseComponent fallback={<>Loading with suspense</>}>
143+
<Tasks {...props} />
144+
</SuspenseComponent>
147145
);
146+
147+
if (client) {
148+
return <ApolloProvider client={client}>{inner}</ApolloProvider>;
149+
}
150+
151+
return inner;
148152
}
149153

150154
afterEach(cleanup);
@@ -180,6 +184,37 @@ it('should return the query data', async () => {
180184
`);
181185
});
182186

187+
it('should accept a client option', async () => {
188+
const client = createMockClient();
189+
const { container } = render(
190+
<TasksWrapper query={TASKS_QUERY} client={client} />
191+
);
192+
193+
expect(container).toMatchInlineSnapshot(`
194+
<div>
195+
Loading without suspense
196+
</div>
197+
`);
198+
199+
await wait();
200+
201+
expect(container).toMatchInlineSnapshot(`
202+
<div>
203+
<ul>
204+
<li>
205+
Learn GraphQL
206+
</li>
207+
<li>
208+
Learn React
209+
</li>
210+
<li>
211+
Learn Apollo
212+
</li>
213+
</ul>
214+
</div>
215+
`);
216+
});
217+
183218
it('should work with suspense enabled', async () => {
184219
const client = createMockClient();
185220
const { container } = render(

src/useMutation.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { DataProxy } from 'apollo-cache';
2-
import { MutationOptions, OperationVariables } from 'apollo-client';
2+
import ApolloClient, {
3+
MutationOptions,
4+
OperationVariables,
5+
} from 'apollo-client';
36
import { FetchResult } from 'apollo-link';
47
import { DocumentNode } from 'graphql';
58

@@ -15,20 +18,32 @@ export type MutationUpdaterFn<TData = Record<string, any>> = (
1518
// hook because we want them to use our custom parametrized version
1619
// of `FetchResult` type. Please look at
1720
// https://github.com/trojanowski/react-apollo-hooks/issues/25
18-
export interface MutationHookOptions<TData, TVariables>
21+
export interface BaseMutationHookOptions<TData, TVariables>
1922
extends Omit<MutationOptions<TData, TVariables>, 'mutation' | 'update'> {
2023
update?: MutationUpdaterFn<TData>;
2124
}
2225

26+
export interface MutationHookOptions<TData, TVariables, TCache = object>
27+
extends BaseMutationHookOptions<TData, TVariables> {
28+
client?: ApolloClient<TCache>;
29+
}
30+
2331
export type MutationFn<TData, TVariables> = (
24-
options?: MutationHookOptions<TData, TVariables>
32+
options?: BaseMutationHookOptions<TData, TVariables>
2533
) => Promise<FetchResult<TData>>;
2634

27-
export function useMutation<TData, TVariables = OperationVariables>(
35+
export function useMutation<
36+
TData,
37+
TVariables = OperationVariables,
38+
TCache = object
39+
>(
2840
mutation: DocumentNode,
29-
baseOptions?: MutationHookOptions<TData, TVariables>
41+
{
42+
client: overrideClient,
43+
...baseOptions
44+
}: MutationHookOptions<TData, TVariables, TCache> = {}
3045
): MutationFn<TData, TVariables> {
31-
const client = useApolloClient();
46+
const client = useApolloClient(overrideClient);
3247

3348
return options => client.mutate({ mutation, ...baseOptions, ...options });
3449
}

src/useQuery.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {
1+
import ApolloClient, {
22
ApolloCurrentResult,
33
ApolloError,
44
ApolloQueryResult,
@@ -32,12 +32,13 @@ export interface QueryHookState<TData>
3232
networkStatus: NetworkStatus | undefined;
3333
}
3434

35-
export interface QueryHookOptions<TVariables>
35+
export interface QueryHookOptions<TVariables, TCache = object>
3636
extends Omit<QueryOptions<TVariables>, 'query'> {
3737
// watch query options from apollo client
3838
notifyOnNetworkStatusChange?: boolean;
3939
pollInterval?: number;
4040
// custom options of `useQuery` hook
41+
client?: ApolloClient<TCache>;
4142
ssr?: boolean;
4243
skip?: boolean;
4344
suspend?: boolean;
@@ -55,7 +56,11 @@ export interface QueryHookResult<TData, TVariables>
5556
): Promise<ApolloQueryResult<TData>>;
5657
}
5758

58-
export function useQuery<TData = any, TVariables = OperationVariables>(
59+
export function useQuery<
60+
TData = any,
61+
TVariables = OperationVariables,
62+
TCache = object
63+
>(
5964
query: DocumentNode,
6065
{
6166
// Hook options
@@ -68,15 +73,16 @@ export function useQuery<TData = any, TVariables = OperationVariables>(
6873
notifyOnNetworkStatusChange = false,
6974

7075
// Apollo client options
76+
client: overrideClient,
7177
context,
7278
metadata,
7379
variables,
7480
fetchPolicy: actualCachePolicy,
7581
errorPolicy,
7682
fetchResults,
77-
}: QueryHookOptions<TVariables> = {}
83+
}: QueryHookOptions<TVariables, TCache> = {}
7884
): QueryHookResult<TData, TVariables> {
79-
const client = useApolloClient();
85+
const client = useApolloClient(overrideClient);
8086
const ssrManager = useContext(SSRContext);
8187
const ssrInUse = ssr && ssrManager;
8288

src/useSubscription.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ export interface OnSubscriptionDataOptions<TData> {
2020
subscriptionData: SubscriptionHookResult<TData>;
2121
}
2222

23-
export interface SubscriptionHookOptions<TData, TVariables>
23+
export interface SubscriptionHookOptions<TData, TVariables, TCache = object>
2424
extends Omit<SubscriptionOptions<TVariables>, 'query'> {
2525
skip?: boolean;
2626
onSubscriptionData?: OnSubscriptionData<TData>;
27+
client?: ApolloClient<TCache>;
2728
}
2829

2930
export interface SubscriptionHookResult<TData> {
@@ -32,14 +33,19 @@ export interface SubscriptionHookResult<TData> {
3233
loading: boolean;
3334
}
3435

35-
export function useSubscription<TData = any, TVariables = OperationVariables>(
36+
export function useSubscription<
37+
TData = any,
38+
TVariables = OperationVariables,
39+
TCache = object
40+
>(
3641
query: DocumentNode,
3742
{
3843
onSubscriptionData,
44+
client: overrideClient,
3945
...options
40-
}: SubscriptionHookOptions<TData, TVariables> = {}
46+
}: SubscriptionHookOptions<TData, TVariables, TCache> = {}
4147
): SubscriptionHookResult<TData> {
42-
const client = useApolloClient();
48+
const client = useApolloClient(overrideClient);
4349
const onSubscriptionDataRef = useRef<
4450
OnSubscriptionData<TData> | null | undefined
4551
>(null);

0 commit comments

Comments
 (0)