@apollo/client
Version:
A fully-featured caching GraphQL client.
158 lines (157 loc) • 5.26 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.useMutation = useMutation;
const tslib_1 = require("tslib");
const equality_1 = require("@wry/equality");
const React = tslib_1.__importStar(require("react"));
const internal_1 = require("@apollo/client/utilities/internal");
const useIsomorphicLayoutEffect_js_1 = require("./internal/useIsomorphicLayoutEffect.cjs");
const useApolloClient_js_1 = require("./useApolloClient.cjs");
/**
* > Refer to the [Mutations](https://www.apollographql.com/docs/react/data/mutations/) section for a more in-depth overview of `useMutation`.
*
* @example
*
* ```jsx
* import { gql, useMutation } from "@apollo/client";
*
* const ADD_TODO = gql`
* mutation AddTodo($type: String!) {
* addTodo(type: $type) {
* id
* type
* }
* }
* `;
*
* function AddTodo() {
* let input;
* const [addTodo, { data }] = useMutation(ADD_TODO);
*
* return (
* <div>
* <form
* onSubmit={(e) => {
* e.preventDefault();
* addTodo({ variables: { type: input.value } });
* input.value = "";
* }}
* >
* <input
* ref={(node) => {
* input = node;
* }}
* />
* <button type="submit">Add Todo</button>
* </form>
* </div>
* );
* }
* ```
*
* @param mutation - A GraphQL mutation document parsed into an AST by `gql`.
* @param options - Options to control how the mutation is executed.
* @returns A tuple in the form of `[mutate, result]`
*/
function useMutation(mutation, options) {
const client = (0, useApolloClient_js_1.useApolloClient)(options?.client);
const [result, setResult] = React.useState(() => createInitialResult(client));
const ref = React.useRef({
result,
mutationId: 0,
isMounted: true,
client,
mutation,
options,
});
(0, useIsomorphicLayoutEffect_js_1.useIsomorphicLayoutEffect)(() => {
Object.assign(ref.current, { client, options, mutation });
});
const execute = React.useCallback((executeOptions = {}) => {
const { options, mutation } = ref.current;
const baseOptions = { ...options, mutation };
const client = executeOptions.client || ref.current.client;
if (!ref.current.result.loading && ref.current.isMounted) {
setResult((ref.current.result = {
loading: true,
error: undefined,
data: undefined,
called: true,
client,
}));
}
const mutationId = ++ref.current.mutationId;
const clientOptions = (0, internal_1.mergeOptions)(baseOptions, executeOptions);
return (0, internal_1.preventUnhandledRejection)(client
.mutate(clientOptions)
.then((response) => {
const { data, error } = response;
const onError = executeOptions.onError || ref.current.options?.onError;
if (error && onError) {
onError(error, clientOptions);
}
if (mutationId === ref.current.mutationId) {
const result = {
called: true,
loading: false,
data,
error,
client,
};
if (ref.current.isMounted &&
!(0, equality_1.equal)(ref.current.result, result)) {
setResult((ref.current.result = result));
}
}
const onCompleted = executeOptions.onCompleted || ref.current.options?.onCompleted;
if (!error) {
onCompleted?.(response.data, clientOptions);
}
return response;
}, (error) => {
if (mutationId === ref.current.mutationId &&
ref.current.isMounted) {
const result = {
loading: false,
error,
data: void 0,
called: true,
client,
};
if (!(0, equality_1.equal)(ref.current.result, result)) {
setResult((ref.current.result = result));
}
}
const onError = executeOptions.onError || ref.current.options?.onError;
if (onError) {
onError(error, clientOptions);
}
throw error;
}));
}, []);
const reset = React.useCallback(() => {
if (ref.current.isMounted) {
const result = createInitialResult(ref.current.client);
Object.assign(ref.current, { mutationId: 0, result });
setResult(result);
}
}, []);
React.useEffect(() => {
const current = ref.current;
current.isMounted = true;
return () => {
current.isMounted = false;
};
}, []);
return [execute, { reset, ...result }];
}
function createInitialResult(client) {
return {
data: undefined,
error: undefined,
called: false,
loading: false,
client,
};
}
//# sourceMappingURL=useMutation.cjs.map