website/docs/concepts/about_code_generation.mdx
import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; import CodeBlock from "@theme/CodeBlock"; import fetchUser from "!!raw-loader!./about_codegen/main.dart"; import rawFetchUser from "!!raw-loader!./about_codegen/raw.dart"; import { Link } from "/src/components/Link"; import { trimSnippet, CodeSnippet } from "/src/components/CodeSnippet"; import syncFn from "!!raw-loader!./about_codegen/provider_type/sync_fn.dart"; import syncClass from "!!raw-loader!./about_codegen/provider_type/sync_class.dart"; import asyncFnFuture from "!!raw-loader!./about_codegen/provider_type/async_fn_future.dart"; import asyncClassFuture from "!!raw-loader!./about_codegen/provider_type/async_class_future.dart"; import asyncFnStream from "!!raw-loader!./about_codegen/provider_type/async_fn_stream.dart"; import asyncClassStream from "!!raw-loader!./about_codegen/provider_type/async_class_stream.dart"; import familyFn from "!!raw-loader!./about_codegen/provider_type/family_fn.dart"; import familyClass from "!!raw-loader!./about_codegen/provider_type/family_class.dart"; import provider from "!!raw-loader!./about_codegen/provider_type/non_code_gen/provider.dart"; import notifierProvider from "!!raw-loader!./about_codegen/provider_type/non_code_gen/notifier_provider.dart"; import futureProvider from "!!raw-loader!./about_codegen/provider_type/non_code_gen/future_provider.dart"; import asyncNotifierProvider from "!!raw-loader!./about_codegen/provider_type/non_code_gen/async_notifier_provider.dart"; import streamProvider from "!!raw-loader!./about_codegen/provider_type/non_code_gen/stream_provider.dart"; import streamNotifierProvider from "!!raw-loader!./about_codegen/provider_type/non_code_gen/stream_notifier_provider.dart"; import autoDisposeCodeGen from "!!raw-loader!./about_codegen/provider_type/auto_dispose.dart"; import autoDisposeNonCodeGen from "!!raw-loader!./about_codegen/provider_type/non_code_gen/auto_dispose.dart"; import familyCodeGen from "!!raw-loader!./about_codegen/provider_type/family.dart"; import familyNonCodeGen from "!!raw-loader!./about_codegen/provider_type/non_code_gen/family.dart"; const TRANSPARENT_STYLE = { backgroundColor: "transparent" }; const RED_STYLE = { color: "indianred", fontWeight: "700" }; const BLUE_STYLE = { color: "rgb(103, 134, 196)", fontWeight: "700" }; const FONT_16_STYLE = { fontSize: "16px", fontWeight: "700", }; const BLUE_20_STYLE = { color: "rgb(103, 134, 196)", fontSize: "20px", fontWeight: "700", }; const PROVIDER_STYLE = { textAlign: "center", fontWeight: "600", maxWidth: "210px", }; const BEFORE_STYLE = { minWidth: "120px", textAlign: "center", fontWeight: "600", color: "crimson", }; const AFTER_STYLE = { minWidth: "120px", textAlign: "center", fontWeight: "600", color: "rgb(40,180,40)", };
Code generation is the idea of using a tool to generate code for us. In Dart, it comes with the downside of requiring an extra step to "compile" an application. Although this problem may be solved in the near future, as the Dart team is working on a potential solution to this problem.
In the context of Riverpod, code generation is about slightly changing the syntax for defining a "provider". For example, instead of:
<CodeBlock language="dart">{trimSnippet(rawFetchUser)}</CodeBlock>
Using code generation, we would write:
<CodeBlock language="dart">{trimSnippet(fetchUser)}</CodeBlock>
When using Riverpod, code generation is completely optional. It is entirely possible to use Riverpod without. At the same time, Riverpod embraces code generation and recommends using it.
For information on how to install and use Riverpod's code generator, refer to the <Link documentID="introduction/getting_started"/> page. Make sure to enable code generation in the documentation's sidebar.
Code generation is optional in Riverpod. With that in mind, you may wonder if you should use it or not.
The answer is: Only if you already use code-generation for other things. (cf Freezed, json_serializable, etc.)
When the Dart team was working on a feature called "macros", using code generation
was the recommended way to use Riverpod. Unfortunately, those have been cancelled.
While code-generation brings many benefits, it currently is still fairly slow. The Dart team is working on improving the performance of code generation, but it is unclear when that will be available and how much it will improve. As such, if you are not already using code generation in your project, it is probably not worth it to start using it just for Riverpod.
At the same time, many applications already use code generation with packages such as Freezed or json_serializable. In that case, your project probably is already set up for code generation, and using Riverpod should be simple.
You may be wondering: "If code generation is optional in Riverpod, why use it?"
As always with packages: To make your life easier. This includes but is not limited to:
When defining a provider using code generation, it is helpful to keep in mind the following points:
build method,
and as such cannot be modified by the UI. (Can’t perform side-effects
using public methods)
</th>
<th style={{ textAlign: "center" }}>
<span style={BLUE_20_STYLE}>Class-Based</span>
(Can perform side-effects
using public methods)
</th>
When using code generation, providers are autoDispose by default. That means that they will automatically
dispose of themselves when there are no listeners attached to them (ref.watch/ref.listen).
This default setting better aligns with Riverpod's philosophy. Initially with the non-code generation variant,
autoDispose was off by default to accommodate users migrating from package:provider.
If you want to disable autoDispose, you can do so by passing keepAlive: true to the annotation.
<CodeBlock language="dart">{trimSnippet(autoDisposeCodeGen)}</CodeBlock>
When using code generation, we no-longer need to rely on the family modifier to pass parameters to a provider.
Instead, the main function of our provider can accept any number of parameters, including named, optional, or default values.
Do note however that these parameters should still have a consistent ==.
Meaning either the values should be cached, or the parameters should override ==.
When using non-code-generation variant, it is necessary to manually determine the type of your provider. The following are the corresponding options for transitioning into code-generation variant:
<table> <colgroup></colgroup> <tr> <td style={PROVIDER_STYLE} colspan="2"> Provider </td> </tr> <tr style={TRANSPARENT_STYLE}> <td style={BEFORE_STYLE}>Before</td> <td> <CodeBlock language="dart">{trimSnippet(provider)}</CodeBlock> </td> </tr> <tr style={TRANSPARENT_STYLE}> <td style={AFTER_STYLE}>After</td> <td> <CodeBlock language="dart">{trimSnippet(syncFn)}</CodeBlock> </td> </tr> <colgroup></colgroup> <tr> <td style={PROVIDER_STYLE} colspan="2"> NotifierProvider </td> </tr> <tr style={TRANSPARENT_STYLE}> <td style={BEFORE_STYLE}>Before</td> <td> <CodeBlock language="dart">{trimSnippet(notifierProvider)}</CodeBlock> </td> </tr> <tr style={TRANSPARENT_STYLE}> <td style={AFTER_STYLE}>After</td> <td> <CodeBlock language="dart">{trimSnippet(syncClass)}</CodeBlock> </td> </tr> <colgroup></colgroup> <tr> <td style={PROVIDER_STYLE} colspan="2"> FutureProvider </td> </tr> <tr style={TRANSPARENT_STYLE}> <td style={BEFORE_STYLE}>Before</td> <td> <CodeBlock language="dart">{trimSnippet(futureProvider)}</CodeBlock> </td> </tr> <tr style={TRANSPARENT_STYLE}> <td style={AFTER_STYLE}>After</td> <td> <CodeBlock language="dart">{trimSnippet(asyncFnFuture)}</CodeBlock> </td> </tr> <colgroup></colgroup> <tr> <td style={PROVIDER_STYLE} colspan="2"> StreamProvider </td> </tr> <tr style={TRANSPARENT_STYLE}> <td style={BEFORE_STYLE}>Before</td> <td> <CodeBlock language="dart">{trimSnippet(streamProvider)}</CodeBlock> </td> </tr> <tr style={TRANSPARENT_STYLE}> <td style={AFTER_STYLE}>After</td> <td> <CodeBlock language="dart">{trimSnippet(asyncFnStream)}</CodeBlock> </td> </tr> <colgroup></colgroup> <tr> <td style={PROVIDER_STYLE} colspan="2"> AsyncNotifierProvider </td> </tr> <tr style={TRANSPARENT_STYLE}> <td style={BEFORE_STYLE}>Before</td> <td> <CodeBlock language="dart"> {trimSnippet(asyncNotifierProvider)} </CodeBlock> </td> </tr> <tr style={TRANSPARENT_STYLE}> <td style={AFTER_STYLE}>After</td> <td> <CodeBlock language="dart">{trimSnippet(asyncClassFuture)}</CodeBlock> </td> </tr> <colgroup></colgroup> <tr> <td style={PROVIDER_STYLE} colspan="2"> StreamNotifierProvider </td> </tr> <tr style={TRANSPARENT_STYLE}> <td style={BEFORE_STYLE}>Before</td> <td> <CodeBlock language="dart"> {trimSnippet(streamNotifierProvider)} </CodeBlock> </td> </tr> <tr style={TRANSPARENT_STYLE}> <td style={AFTER_STYLE}>After</td> <td> <CodeBlock language="dart">{trimSnippet(asyncClassStream)}</CodeBlock> </td> </tr> </table>