Using Mutations

Mutations are called directly, like a regular asynchronous function.

import updateProject from 'app/projects/mutations/updateProject'
function (props) {
return (
<Formik
onSubmit={async values => {
try {
const project = await updateProject(values)
} catch (error) {
alert('Error saving project')
}
}}>
{/* ... */}
</Formik>
)
}
🤔

You may be wondering how that can work since it's importing server code into your component: At build time, the direct function import is swapped out with a network call. So the query function code is never included in your client code.

Error Handling

Any errors thrown from your server code will be thrown on the client exactly like you'd expect. So you can use

try {} catch {} or .catch().

Cache Invalidation

mutate

  • useQuery returns a mutate function you can use to manually update the cache
  • Calling mutate will automatically trigger a refetch for the initial query to ensure it has the correct data. Disable refetch by passing an options object {refetch: false} as the second argument.
export default function (props: {query: {id: number}}) {
const [product, {mutate}] = useQuery(getProduct, {where: {id: props.query.id}})
return (
<Formik
initialValues={product}
onSubmit={async (values) => {
try {
const product = await updateProduct(values)
mutate(product)
} catch (error) {
alert("Error saving product")
}
}}
>
{/* ... */}
</Formik>
)
}

refetch

export default function (props) {
const [product, {refetch}] = useQuery(getProduct, {where: {id: props.id}})
return (
<Formik
initialValues={product}
onSubmit={async (values) => {
try {
const product = await updateProduct(values)
refetch()
} catch (error) {
alert("Error saving product")
}
}}
>
{/* ... */}
</Formik>
)
}

Automatically

We want to somehow automatically invalidate your query cache. We're not sure how to do this yet, but we have

an open issue that you're welcome to contribute to!

Optimistic Updates

Optimistic UI patterns are a technique for making your apps feel more responsive to user interactions. When a user takes an action (for example liking a post) we can avoid showing activity spinners or loading animations by simply assuming the action was successful. We update our local cache and interface immediately to show a successful result.

When the real response arrives from the action we then update the UI to reflect the true value returned from the database. In most cases, with a successful request, this will be invisible to the user, and the change will appear to have occurred instantly.

In the case of an error, we revert the local change, refetch the data, and optionally show an error message.

Here's a simple form component with an

onSubmit function that calls an updateProduct mutation to save edits.

export default function (props: {query: {id: number}}) {
const [product, {mutate}] = useQuery(getProduct, {where: {id: props.query.id}})
return (
<Formik
initialValues={product}
onSubmit={async (values) => {
try {
const product = await updateProduct(values)
mutate(product)
} catch (error) {
alert("Error saving product")
}
}}>
{/* ... */}
</Formik>
)
}

We can enhance this to support instant feedback to the user, immediately showing the edited product information, by mutating the local cache of the

getProducts query with the changes we're about to send to the database. We pass {refetch: false} as a second argument to the mutate() function to prevent the mutation triggering a refetch of stale data while we wait for the response.

export default function (props: {query: {id: number}}) {
const [product, {mutate}] = useQuery(getProduct, {where: {id: props.query.id}})
return (
<Formik
initialValues={product}
onSubmit={async (values) => {
try {
// Update local cache with form values without triggering refetch
mutate(values, {refetch: false})
const product = await updateProduct(values)
// Update local cache with result, then refetch
mutate(product)
} catch (error) {
// Set cache back to original result, then refetch
mutate(product)
alert("Error saving product")
}
}}>
{/* ... */}
</Formik>
)
}
Idea for improving this page?Edit it on Github