Mutations
Unlike queries, mutations in GraphQL are used to create, update or delete data.
For this purpose, Draqula offers a useMutation hook.
Just like queries, remember to define your GraphQL queries outside your components to prevent infinite unnecessary rerenders.
Basic mutations
Assuming the server implements a ping mutation, that simply returns "pong" string, here's an example of the most basic mutation:
1 const PING_MUTATION = gql`2 mutation {3 ping4 }5 `;67 const PingPong = () => {8 const {mutate} = useMutation(PING_MUTATION);910 const onPing = async () => {11 const data = await mutate();12 // {13 // ping: 'pong'14 // }15 };1617 return <button onClick={onPing}>Ping</button>;18};
Mutations without variables are not that useful, so let's add some variables to closer match reality.
Variables
Similar to useQuery, useMutation also accepts variables.
The only difference is that you don't pass them to useMutation itself, but to the mutate function that it returns.
1 const CREATE_TODO_MUTATION = gql`2 mutation CreateTodo($title: String!) {3 createTodo(title: $title) {4 id5 title6 }7 }8 `;910const CreateTodo = () => {11 const [title, setTitle] = useState('');12 const {mutate} = useMutation(CREATE_TODO_MUTATION);1314 const onCreateTodo = async event => {15 // Prevent the form from refreshing the page16 event.preventDefault();1718 try {19 await mutate({title});2021 // Todo was successfully created22 } catch (error) {23 // Uh oh, something went wrong24 }25 };2627 return (28 <form onSubmit={onCreateTodo}>29 <input type="text" value={title} onChange={event => setTitle(event.target.value)} />30 <br />31 <button type="submit">Create Todo</button>32 </form>33 );34};
Caching
When a mutation succeeds, Draqula scans the GraphQL types returned from that mutation and refetches all queries that use any of these types. For example, let's say we have the following GraphQL schema on our server:
1 type Query {2 posts: [Post!]!3 pages: [Page!]!4 }56 type Mutation {7 createPost(title: String!): Post!8 }910type Post {11 title: String!12}1314type Page {15 title: String!16}
Imagine we also have the following code for our page:
1 const POSTS_QUERY = gql`2 query {3 posts {4 title5 }6 }7 `;89 const PAGES_QUERY = gql`10 query {11 pages {12 title13 }14 }15`;1617const CREATE_POST_MUTATION = gql`18 mutation CreatePost($title: String!) {19 createPost(title: $title) {20 title21 }22 }23`;2425const Blog = () => {26 const {data: posts} = useQuery(POSTS_QUERY);27 const {data: pages} = useQuery(PAGES_QUERY);28 const {mutate: createPost} = useMutation(CREATE_POST_MUTATION);2930 return (31 <>32 {/* ... */}33 <button onClick={() => createPost({title: 'Stranger Things'})}>Create Post</button>34 </>35 );36};
If a user clicks the "Create Post" button, the createPost mutation will be executed, which returns only the Post type.
That tells Draqula to find all queries that contain the Post type and refetches them.
In this case, POSTS_QUERY is the only one that uses this type, so it will be refetched, while PAGES_QUERY will remain in the same state.
Refetch queries
However, sometimes a server uses the same data source but returns it under various types.
In that case, Draqula has no way to know that some query uses the same data under the hood and we need to help it find those queries to refetch.
This is where the refetchQueries option comes in.
It's a list of queries to refetch in addition to the ones Draqula finds by itself.
So if in theory, PAGES_QUERY needed to be refetched after the createPost mutation, this is how it would work:
1const Blog = () => {2 const {data: posts} = useQuery(POSTS_QUERY);3 const {data: pages} = useQuery(PAGES_QUERY);4 const {mutate: createPost} = useMutation(CREATE_POST_MUTATION, {5 refetchQueries: [PAGES_QUERY]6 });78 // ...9};
It's important to mention that by default createPost doesn't wait for queries to finish refetching.
If this behavior is important for you, you can opt-in for that via the waitForRefetchQueries option:
1 const Blog = () => {2 const {data: posts} = useQuery(POSTS_QUERY);3 const {data: pages} = useQuery(PAGES_QUERY);4 const {mutate: createPost} = useMutation(CREATE_POST_MUTATION, {5 waitForRefetchQueries: true,6 refetchQueries: [PAGES_QUERY]7 });89 const onCreatePost = async () => {10 try {11 await createPost({title: 'Stranger Things'});1213 // Both POSTS_QUERY and PAGES_QUERY are refetched at this point14 } catch (error) {15 // ...16 }17 };1819 // ...20};
If you wish to disable refetching of any queries, set refetchQueries parameter to false:
1useMutation(CREATE_POST_MUTATION, {2 refetchQueries: false3});
API
useMutation(query, options?)
This hook returns a MutationResult object.
query
Type: DocumentNode
Parsed GraphQL query via gql function from the graphql-tag module.
For example:
1const PING_MUTATION = gql`2 mutation {3 ping4 }5`;
options
Type: object
options.refetchQueries
Type: boolean | DocumentNode[]
Default: []
List of queries to refetch after the mutation succeeds.
Set to false to disable any refetching.
options.waitForRefetchQueries
Type: boolean
Default: false
Determines whether to wait for queries to refetch or complete the mutation immediately.
MutationResult
The useMutation hook returns an object consisting of the following fields.
mutate
Type: Function
A function that triggers a mutation. Accepts an optional object of variables to pass to the mutation. Returns a promise that resolves when the mutation is completed.
1const {mutate} = useMutation(CREATE_POST_MUTATION);23const onCreatePost = async () => {4 await mutate({5 title: 'New Post'6 });7};
data
Type: object
Data returned from the query.
isLoading
Type: boolean
Default: false
Indicates whether the mutation is currently in-flight.
error
Type: NetworkError | GraphQLError | undefined
The error returned from the mutation request. Read more in the "Error handling" section.


