Skip to content

Commit d46ef12

Browse files
committed
feat(packages/react): support operation name
1 parent 1fbba64 commit d46ef12

File tree

5 files changed

+58
-2
lines changed

5 files changed

+58
-2
lines changed

.changeset/purple-mugs-travel.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@gqty/react': minor
3+
---
4+
5+
feat(packages/react): support GraphQL operation names

packages/react/src/mutation/useMutation.ts

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export interface UseMutationOptions<TData> {
3939
* @default false
4040
*/
4141
nonSerializableVariables?: boolean;
42+
/** Optional operation name for this mutation request. */
43+
operationName?: string;
4244
}
4345

4446
export interface UseMutationState<TData> {
@@ -215,6 +217,7 @@ export function createUseMutation<
215217
noCache: optsRef.current.noCache,
216218
refetch: true,
217219
nonSerializableVariables: optsRef.current.nonSerializableVariables,
220+
operationName: optsRef.current.operationName,
218221
}).then(
219222
async (data) => {
220223
const refetchingQueries = callRefetchQueries();

packages/react/src/query/useQuery.ts

+16
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface UseQueryOptions<
2424
suspense?: boolean;
2525
staleWhileRevalidate?: boolean | object | number | string | null;
2626
onError?: OnErrorHandler;
27+
operationName?: string;
2728
prepare?: (helpers: UseQueryPrepareHelpers<GeneratedSchema>) => void;
2829
}
2930

@@ -80,6 +81,7 @@ export function createUseQuery<
8081
staleWhileRevalidate = defaultStaleWhileRevalidate,
8182
onError,
8283
prepare,
84+
operationName,
8385
}: UseQueryOptions<GeneratedSchema> = {}): UseQueryReturnValue<GeneratedSchema> {
8486
const [$state] = React.useState<Writeable<UseQueryState>>(() => {
8587
const state: Writeable<UseQueryState> = {
@@ -101,6 +103,18 @@ export function createUseQuery<
101103
updateOnFetchPromise: true,
102104
});
103105

106+
const removeOperationNameInterceptor = React.useMemo(() => {
107+
const interceptor = interceptorManager.createInterceptor();
108+
109+
interceptor.selectionAddListeners.add((selection) => {
110+
selection.operationName = operationName;
111+
});
112+
113+
return () => {
114+
interceptorManager.removeInterceptor(interceptor);
115+
};
116+
}, [operationName]);
117+
104118
if (prepare) {
105119
try {
106120
prepare(prepareHelpers);
@@ -112,6 +126,8 @@ export function createUseQuery<
112126
}
113127
}
114128

129+
useIsomorphicLayoutEffect(removeOperationNameInterceptor);
130+
115131
useIsomorphicLayoutEffect(() => {
116132
return scheduler.errors.subscribeErrors((ev) => {
117133
switch (ev.type) {

packages/react/src/subscription/useSubscription.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ export interface UseSubscription<
1313
subscription: object;
1414
}
1515
> {
16-
(): GeneratedSchema['subscription'];
16+
(opts?: UseSubscriptionOptions): GeneratedSchema['subscription'];
17+
}
18+
19+
export interface UseSubscriptionOptions {
20+
operationName?: string;
1721
}
1822

1923
export function createUseSubscription<
@@ -36,7 +40,7 @@ export function createUseSubscription<
3640
client.subscription;
3741

3842
const useSubscription: UseSubscription<GeneratedSchema> =
39-
function useSubscription() {
43+
function useSubscription(opts?: UseSubscriptionOptions) {
4044
const forceUpdate = useForceUpdate({
4145
doTimeout: true,
4246
});
@@ -46,6 +50,10 @@ export function createUseSubscription<
4650

4751
Promise.resolve(interceptor).then(removeInterceptor);
4852

53+
interceptor.selectionAddListeners.add((selection) => {
54+
selection.operationName = opts?.operationName;
55+
});
56+
4957
interceptor.selectionAddListeners.add((selection) => {
5058
if (selection.type === 2) hookSelections.add(selection);
5159
});

packages/react/test/useQuery.test.tsx

+24
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,27 @@ test('Basic Suspense', async () => {
4444

4545
expect(result.current).toBe('hello world');
4646
});
47+
48+
it.only('should fetches with operation name', async () => {
49+
let fetchedQuery: string | undefined;
50+
const { useQuery } = await createReactTestClient(undefined, (query) => {
51+
fetchedQuery = query;
52+
return { data: { hello: 'hello world' } };
53+
});
54+
55+
const { result, waitForNextUpdate } = renderHook(() => {
56+
const query = useQuery({
57+
operationName: 'TestQuery',
58+
suspense: true,
59+
});
60+
61+
return query.hello;
62+
});
63+
64+
expect(result.current).toBe(undefined);
65+
66+
await waitForNextUpdate();
67+
68+
expect(fetchedQuery).toBe('query TestQuery{hello}');
69+
expect(result.current).toBe('hello world');
70+
});

0 commit comments

Comments
 (0)