Skip to content

Commit

Permalink
fix useMutation hook returning different execute functions
Browse files Browse the repository at this point in the history
  • Loading branch information
brainkim committed Nov 10, 2021
1 parent 9ad27c8 commit 87f0f7a
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 70 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
{
"name": "apollo-client",
"path": "./dist/apollo-client.min.cjs",
"maxSize": "28.45 kB"
"maxSize": "28.5kB"
}
],
"engines": {
Expand Down
156 changes: 87 additions & 69 deletions src/react/hooks/useMutation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { useCallback, useMemo, useEffect, useRef, useState } from 'react';
import { DocumentNode } from 'graphql';
import { TypedDocumentNode } from '@graphql-typed-document-node/core';
import {
Expand Down Expand Up @@ -40,87 +40,105 @@ export function useMutation<
result,
mutationId: 0,
isMounted: true,
execute: null as null | MutationTuple<TData, TVariables, TContext, TCache>[0],
client,
mutation,
options,
});

const execute = useCallback((
executeOptions: MutationFunctionOptions<
TData,
TVariables,
TContext,
TCache
> = {},
) => {

const baseOptions = { ...options, mutation };
if (!ref.current.result.loading && !baseOptions.ignoreResults) {
setResult(ref.current.result = {
loading: true,
error: void 0,
data: void 0,
called: true,
client,
});
const execute = useMemo(() => {
if (
ref.current.execute != null &&
ref.current.client === client &&
equal(options, ref.current.options) &&
equal(mutation, ref.current.mutation)) {
return ref.current.execute;
}

const mutationId = ++ref.current.mutationId;
const clientOptions = mergeOptions(
baseOptions,
executeOptions as any,
);

return client.mutate(clientOptions).then((response) =>{
const { data, errors } = response;
const error =
errors && errors.length > 0
? new ApolloError({ graphQLErrors: errors })
: void 0;

if (
mutationId === ref.current.mutationId &&
!baseOptions.ignoreResults
) {
const result = {
ref.current.client = client;
ref.current.options = options;
ref.current.mutation = mutation;
ref.current.execute = (
executeOptions: MutationFunctionOptions<
TData,
TVariables,
TContext,
TCache
> = {},
) => {
const baseOptions = { ...options, mutation };
if (!ref.current.result.loading && !baseOptions.ignoreResults) {
setResult(ref.current.result = {
loading: true,
error: void 0,
data: void 0,
called: true,
loading: false,
data,
error,
client,
};
});
}

if (ref.current.isMounted && !equal(ref.current.result, result)) {
setResult(ref.current.result = result);
const mutationId = ++ref.current.mutationId;
const clientOptions = mergeOptions(
baseOptions,
executeOptions as any,
);

return client.mutate(clientOptions).then((response) =>{
const { data, errors } = response;
const error =
errors && errors.length > 0
? new ApolloError({ graphQLErrors: errors })
: void 0;

if (
mutationId === ref.current.mutationId &&
!baseOptions.ignoreResults
) {
const result = {
called: true,
loading: false,
data,
error,
client,
};

if (ref.current.isMounted && !equal(ref.current.result, result)) {
setResult(ref.current.result = result);
}
}
}

baseOptions.onCompleted?.(response.data!);
return response;
}).catch((error) => {
if (
mutationId === ref.current.mutationId &&
ref.current.isMounted
) {
const result = {
loading: false,
error,
data: void 0,
called: true,
client,
};
baseOptions.onCompleted?.(response.data!);
return response;
}).catch((error) => {
if (
mutationId === ref.current.mutationId &&
ref.current.isMounted
) {
const result = {
loading: false,
error,
data: void 0,
called: true,
client,
};

if (!equal(ref.current.result, result)) {
setResult(ref.current.result = result);
}
}

if (!equal(ref.current.result, result)) {
setResult(ref.current.result = result);
if (baseOptions.onError) {
baseOptions.onError(error);
// TODO(brian): why are we returning this here???
return { data: void 0, errors: error };
}
}

if (baseOptions.onError) {
baseOptions.onError(error);
// TODO(brian): why are we returning this here???
return { data: void 0, errors: error };
}
throw error;
});
};

throw error;
});
}, [client, options, mutation]);
return ref.current.execute;
}, [client, mutation, options]);

const reset = useCallback(() => {
setResult({ called: false, loading: false, client });
Expand Down

0 comments on commit 87f0f7a

Please sign in to comment.