website/docs/concepts2/mutations.mdx
import { Link } from "/src/components/Link"; import CodeBlock from "@theme/CodeBlock"; import { trimSnippet } from "/src/components/CodeSnippet"; import listener from 'raw-loader!./mutations/listening.dart'; import keyed from 'raw-loader!./mutations/keyed.dart'; import generic from 'raw-loader!./mutations/generic.dart'; import triggering from 'raw-loader!./mutations/triggering.dart'; import switching from 'raw-loader!./mutations/switching.dart'; import resetting from 'raw-loader!./mutations/resetting.dart';
:::caution Mutations are experimental, and the API may change in a breaking way without a major version bump. :::
Mutations, in Riverpod, are objects which enable the user interface to react to state changes. A common use-case is displaying a loading indicator while a form is being submitted
In short, mutations are to achieve effects such as this: !
Without mutations, you would have to store the progress of the form submission directly inside the state of a provider. This is not ideal as it pollutes the state of your provider with UI concerns ; and it involves a lot of boilerplate code to handle the loading state, error state, and success state.
Mutations are designed to handle these concerns in a more elegant way.
Mutations are instances of the Mutation object, stored in a final variable somewhere.
// A mutation to track the "add todo" operation.
// The generic type is optional and can be specified to enable the UI to interact
// with the result of the mutation.
final addTodo = Mutation<Todo>();
:::note
Typically, this variable will either be global or as a static final variable on
a Notifier.
:::
Once we've defined a mutation, we can start using it inside <Link documentID="concepts2/consumers" /> or <Link documentID="concepts2/providers" />.
For this, we will need a <Link documentID="concepts2/refs" /> and pick a listening method of our choice
(typically Ref.watch).
A typical example would be:
<CodeBlock>{trimSnippet(listener)}</CodeBlock>
Sometimes, you may want to have multiple instances of the same mutation.
This can include things like an id, or any other parameter that makes the mutation unique.
This is useful if you want to have multiple instances of the same mutation, such as deleting a specific item in a list
Simply call the mutation with the unique key:
<CodeBlock>{trimSnippet(keyed)}</CodeBlock>
Sometimes, these mutations have a generic return type, such as if an api response may have different response types based on the input parameters, such as with deserialization.
<CodeBlock>{trimSnippet(generic)}</CodeBlock>
So far, we've listened to the state of a mutation, but nothing actually happens yet.
To trigger a mutation, we can use Mutation.run, pass our mutation, and provide an asynchronous callback that updates whatever state we want. Lastly, we'll need to return a value matching the generic type of the mutation.
<CodeBlock>{trimSnippet(triggering)}</CodeBlock>
Mutations can be in one of the following states:
You can switch over the different states using a switch statement:
<CodeBlock>{trimSnippet(switching)}</CodeBlock>
Mutations naturally reset themselves to MutationIdle if:
This is similar to how <Link documentID="concepts2/auto_dispose"/> works, but for mutations.
Alternatively, you can manually reset a mutation to its idle state by calling the Mutation.reset method:
<CodeBlock>{trimSnippet(resetting)}</CodeBlock>