Skip to content
Hooks

useMutation

Bridges TanStack Query mutations with Legend-State. Returns mutation state as an Observable, so every status field (isPending, isSuccess, isError, etc.) is reactive. Options follow TanStack Query’s standard UseMutationOptions — refer to TanStack Query docs for full option details.

Both variants require a QueryClientProvider ancestor — the client is injected from context.

useMutation
Idle

Submit a todo — observe mutation state transitions.

import {
function Show<T>(props: Props<T>): ReactElement (+2 overloads)
Show
} from "@usels/core";
import {
const useMutation: <TData = unknown, TVariables = void, TContext = unknown>(options?: DeepMaybeObservable<CreateMutationOptions<TData, TVariables, TContext>>) => Observable<MutationState<TData, TVariables, TContext>>
useMutation
} from "@usels/tanstack-query";
function
function CreateUser(): JSX.Element
CreateUser
() {
const
const mutation: any
mutation
=
useMutation<unknown, void, unknown>(options?: DeepMaybeObservable<CreateMutationOptions<unknown, void, unknown>>): Observable<MutationState<unknown, void, unknown>>

Core observable function for bridging TanStack Query mutations with Legend-State.

Must be called inside a scope wrapped by a QueryClientProvidergetQueryClient() injects the client from context. Teardown is registered via onUnmount; option changes propagate via observe.

@paramoptions - Plain object, per-field Observable, or outer Observable of options.

@returnsObservable reflecting mutation state (including mutate/mutateAsync/reset).

useMutation
({
mutationFn: (user: {
name: string;
email: string;
}) => any
mutationFn
: (
user: {
name: string;
email: string;
}
user
: {
name: string
name
: string;
email: string
email
: string }) =>
any
fetch
("/api/users", {
method: string
method
: "POST",
body: any
body
:
any
JSON
.
any
stringify
(
user: {
name: string;
email: string;
}
user
),
}).
any
then
((
r: any
r
) =>
r: any
r
.
any
json
()),
});
return (
<
JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
<
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
DOMAttributes<HTMLButtonElement>.onClick?: MouseEventHandler<HTMLButtonElement> | undefined
onClick
={() =>
const mutation: any
mutation
.
any
mutate
.
any
get
()({
name: string
name
: "John",
email: string
email
: "john@test.com" })}
ButtonHTMLAttributes<HTMLButtonElement>.disabled?: boolean | undefined
disabled
={
const mutation: any
mutation
.
any
isPending
.
any
get
()}
>
<
function Show<T>(props: Props<T>): ReactElement (+2 overloads)
Show
if: any
if
={
const mutation: any
mutation
.
any
isPending
}
else?: any
else
="Create User">
Creating...
</
function Show<T>(props: Props<T>): ReactElement (+2 overloads)
Show
>
</
JSX.IntrinsicElements.button: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button
>
<
function Show<T>(props: Props<T>): ReactElement (+2 overloads)
Show
if: any
if
={
const mutation: any
mutation
.
any
isError
}>
<
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>Error: {
const mutation: any
mutation
.
any
error
.
any
get
()?.
any
message
}</
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>
</
function Show<T>(props: Props<T>): ReactElement (+2 overloads)
Show
>
<
function Show<T>(props: Props<T>): ReactElement (+2 overloads)
Show
if: any
if
={
const mutation: any
mutation
.
any
isSuccess
}>
<
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>User created!</
JSX.IntrinsicElements.p: DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p
>
</
function Show<T>(props: Props<T>): ReactElement (+2 overloads)
Show
>
</
JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
);
}
import { useMutation, useQueryClient } from "@usels/tanstack-query";
function AddTodo() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (text: string) =>
fetch("/api/todos", {
method: "POST",
body: JSON.stringify({ text }),
}).then((r) => r.json()),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["todos"] });
},
});
return <button onClick={() => mutation.mutate.get()("New todo")}>Add Todo</button>;
}
import { useMutation } from "@usels/tanstack-query";
function SubmitForm() {
const mutation = useMutation({
mutationFn: (data: FormData) =>
fetch("/api/submit", { method: "POST", body: data }).then((r) => r.json()),
});
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const result = await mutation.mutateAsync.get()(new FormData(e.currentTarget));
console.log("Submitted:", result);
};
return <form onSubmit={handleSubmit}>...</form>;
}
export type { CreateMutationOptions, MutationState } from "./core";
export { createMutation } from "./core";
/**
* UseMutationOptions is an alias for CreateMutationOptions for backward compatibility.
*/
export type UseMutationOptions<TData = unknown, TVariables = void, TContext = unknown> = CreateMutationOptions<TData, TVariables, TContext>;
/**
* Connects TanStack Query Mutation with Legend-State observables.
* Uses MutationObserver to manage mutation state as observables.
*/
export type UseMutation = typeof createMutation;
export declare const useMutation: UseMutation;

View on GitHub