eddev

Mutation Hooks

Generate mutation hooks for runtime GraphQL operations with side effects.

Mutations are GraphQL operations with side effects, such as submitting a form, creating a shared planner, saving user data, or sending an enquiry.

Mutation files live under queries/ and follow the same filename rules as query hooks: the file and operation should start with Use, and the operation name should match the filename.

mutation UseCreateSharedPlanner($ids: [Int!], $name: String, $userId: String) {
  createSharedPlanner(input: { ferveIds: $ids, name: $name, ferveUserId: $userId }) {
    planner {
      id
      name
    }
  }
}

This generates useCreateSharedPlanner in hooks/queries.ts.

Unlike query hooks, mutation hooks do not run when rendered. You call mutate() or mutateAsync() from an event handler.

Hook Usage

import { useState } from "react"
import { useCreateSharedPlanner } from "@hooks/queries"

export function CreateSharedPlanner() {
  const [name, setName] = useState("")
  const create = useCreateSharedPlanner()

  if (create.isSuccess) {
    return <p>Planner created: {create.data.createSharedPlanner?.planner?.id}</p>
  }

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault()
        if (create.isPending) return

        create.mutate({
          name,
          ids: [123, 456],
        })
      }}
    >
      {create.isError && <p>{create.error.message}</p>}
      <input disabled={create.isPending} value={name} onChange={(e) => setName(e.currentTarget.value)} />
      <button disabled={create.isPending} type="submit">Create Planner</button>
    </form>
  )
}

Many built-in WPGraphQL mutations require WordPress admin privileges. Public-facing mutations usually need to be registered by the project. See Extending GraphQL.

Hook API

The generated hook returns a TanStack mutation result:

const mutation = useCreateSharedPlanner({
  onSuccess(data) {
    // Optional success handler
  },
  onError(error) {
    // Optional error handler
  },
})

Useful returned properties include:

type MutationResult<TData, TVars> = {
  status: "idle" | "pending" | "error" | "success"
  isPending: boolean
  isSuccess: boolean
  isError: boolean
  error: QueryError | null
  data: TData | undefined
  mutate: (variables: TVars, options?: MutationOptions<TData>) => void
  mutateAsync: (variables: TVars, options?: MutationOptions<TData>) => Promise<TData>
}

You can pass mutation options to the hook itself, or to mutate() / mutateAsync().

Manual Mutation

Each generated mutation hook also has a static .mutate() method for non-hook usage.

import { useCreateSharedPlanner } from "@hooks/queries"

async function createPlanner() {
  const result = await useCreateSharedPlanner.mutate({
    name: "Weekend picks",
    ids: [123, 456],
  })

  return result.createSharedPlanner?.planner
}

Prefer the hook in React components so loading and error states stay tied to the UI.

On this page