Kodgenerering med riverpod_generator och @riverpod
Använd annoteringarna i riverpod_generator för att skapa typsäkra providers utan standardkod.
Kodgenerering med riverpod_generator och @riverpod är en gratis lektion i Mobilutveckling med Flutter på CoddyKit. Detta är lektion 2 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Mobilutveckling med Flutter, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Mobilutveckling med Flutter innehåller totalt 4 lektioner.
Varför kodgenerering?
Före Riverpod 2.0 valde ni rätt providertyp manuellt: Provider, StateProvider, FutureProvider, StreamProvider, NotifierProvider och så vidare. Om ni valde fel behövde koden skrivas om.
Paketet riverpod_generator vänder på detta. Ni skriver en vanlig funktion eller klass och lägger till annoteringen @riverpod. Generatorn granskar funktionens returtyp och skapar automatiskt rätt, fullständigt typsäkra provider.
- Mindre standardkod — inga manuella provider-deklarationer.
- Typsäkra parametrar — skicka argument utan krånglig användning av
.family. - Automatiskt avregistrerade som standard — genererade providers fungerar som
autoDispose.
Lägga till beroendena
Kodgenerering kräver paket både för körning och utveckling. riverpod_annotation tillhandahåller annoteringen @riverpod som ni använder i källkoden. riverpod_generator och build_runner kör byggsteget som skapar .g.dart-filerna.
En typisk pubspec.yaml för en Flutter-app ser ut så här.
dependencies:
flutter:
sdk: flutter
flutter_riverpod: ^2.5.1
riverpod_annotation: ^2.3.5
dev_dependencies:
build_runner: ^2.4.11
riverpod_generator: ^2.4.0
custom_lint: ^0.6.4
riverpod_lint: ^2.3.10Er första genererade provider
Den minsta genererade providern är en toppnivåfunktion som annoterats med @riverpod. Den första parametern är alltid ett Ref-objekt; returtypen avgör allt.
Eftersom funktionen returnerar en vanlig String synkront skapar generatorn en skrivskyddad provider som exponerar värdet. Ni använder den via ref.watch(helloWorldProvider), precis som en manuellt skriven Provider<String>.
Observera de två obligatoriska delarna: part-direktivet och kommentaren // ignore_for_file är valfri — men part 'file.g.dart'; är obligatorisk.
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'hello.g.dart';
@riverpod
String helloWorld(Ref ref) {
return 'Hello, Riverpod 2.0';
}Köra generatorn
Annoteringen gör ingenting förrän build_runner har skapat den tillhörande .g.dart-filen. Kör den från projektets rotkatalog.
- Engångsbygge: skapar filerna en gång och avslutas.
--delete-conflicting-outputsrensar gamla genererade filer. - Övervakningsläge: genererar automatiskt på nytt varje gång ni sparar en källkodsfil — idealiskt under aktiv utveckling.
När körningen är klar blir symbolen helloWorldProvider tillgänglig för import.
# Generate once
dart run build_runner build --delete-conflicting-outputs
# Or watch and rebuild on save
dart run build_runner watch --delete-conflicting-outputsReturtypen styr providern
Generatorn läser returtypen och väljer automatiskt motsvarande providertyp. Detta är den centrala fördelen med kodgenerering: ni behöver aldrig ange en providertyp igen.
- Returnera
T→ synkron provider (somProvider<T>). - Returnera
Future<T>→ asynkron provider som exponerarAsyncValue<T>(somFutureProvider). - Returnera
Stream<T>→ stream-provider som exponerarAsyncValue<T>(somStreamProvider).
Nedan räcker det att ändra signaturen till Future för att göra den till en asynkron provider — ingen annan ändring behövs.
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'user.g.dart';
@riverpod
Future<String> userName(Ref ref) async {
await Future<void>.delayed(const Duration(seconds: 1));
return 'Ada Lovelace';
}Skicka parametrar (inte längre .family)
Med manuellt skrivna providers innebar parametrisering att ni använde .family och ett enda tupliknande argument. Generatorn låter er lägga till vanliga funktionsparametrar efter ref, och de blir starkt typade provider-argument.
Här tar messageProvider emot ett int id. Ni anropar den som ref.watch(messageProvider(42)). Flera parametrar samt namngivna och valfria parametrar fungerar också.
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'message.g.dart';
@riverpod
Future<String> message(Ref ref, int id) async {
final repo = ref.watch(messageRepositoryProvider);
return repo.fetchById(id);
}
// Usage in a widget:
// final msg = ref.watch(messageProvider(42));Tillståndslogik: Notifier-klassen
För föränderligt tillstånd med metoder annoterar ni en klass som utökar den genererade basklassen _$ClassName. Ni åsidosätter build() för att returnera det initiala tillståndet; generatorn kopplar automatiskt in en NotifierProvider.
I metoder ändrar ni state, och lyssnare byggs automatiskt om. Detta ersätter den gamla deklarationen med Notifier + manuell NotifierProvider med en enda annoterad klass.
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'counter.g.dart';
@riverpod
class Counter extends _$Counter {
@override
int build() => 0;
void increment() => state++;
void reset() => state = 0;
}Asynkrona Notifiers
Om build() returnerar en Future skapar generatorn en AsyncNotifier. Det exponerade tillståndet är ett AsyncValue<T> som automatiskt följer tillstånden laddar, data och fel.
För att uppdatera tillståndet efter en asynkron åtgärd tilldelar ni AsyncValue.guard(...) till state — den kör er asynkrona kod och fångar lyckat resultat eller fel utan manuell try/catch.
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'todos.g.dart';
@riverpod
class Todos extends _$Todos {
@override
Future<List<String>> build() async {
return ref.watch(todoRepositoryProvider).fetchAll();
}
Future<void> add(String title) async {
state = const AsyncLoading();
state = await AsyncValue.guard(() async {
await ref.read(todoRepositoryProvider).create(title);
return ref.read(todoRepositoryProvider).fetchAll();
});
}
}Använda genererade providers
Genererade providers används precis som manuella — den genererade symbolen är <name>Provider för funktioner eller <ClassName>Provider för Notifier-klasser.
ref.watch(counterProvider)→ det aktuella tillståndsvärdet.ref.read(counterProvider.notifier)→ Notifier-instansen, så att ni kan anropa metoder somincrement().- För asynkrona providers returnerar watch ett
AsyncValuesom ni hanterar med.when(...).
class CounterView extends ConsumerWidget {
const CounterView({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Column(
children: [
Text('Count: $count'),
ElevatedButton(
onPressed: () => ref.read(counterProvider.notifier).increment(),
child: const Text('Add'),
),
],
);
}
}Hålla providers aktiva och hantera beroenden
Genererade providers avregistreras automatiskt som standard — de släpper sitt tillstånd när ingen längre bevakar dem. Två annoteringsalternativ ger er kontroll:
@Riverpod(keepAlive: true)— håller providern aktiv även utan lyssnare (använd detta för appomfattande singletoner som en Dio-klient).@Riverpod(dependencies: [...])— deklarerar åsidosättningar i ett scope för provider-avgränsning. De flesta appar behöver inte detta.
Den versaliserade formen @Riverpod(...) är helt enkelt den konfigurerbara versionen av den kortare formen @riverpod med gemen.
import 'package:dio/dio.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'http.g.dart';
@Riverpod(keepAlive: true)
Dio dio(Ref ref) {
return Dio(BaseOptions(baseUrl: 'https://api.example.com'));
}Ren Dart: varför logiken går att testa
En stor fördel med kodgenerering är att era provider-kroppar består av vanliga Dart-funktioner och klasser — de är enkla att förstå och enhetstesta. Nedan visas ett fristående exempel på samma state++-logik för att ändra tillstånd som en genererad Notifier skulle köra, utan att några Flutter- eller Riverpod-importer behövs.
Det är precis sådan ren logik ni behåller i en genererad @riverpod-klass, så att den förblir mycket enkel att testa.
class Counter {
int state = 0;
void increment() => state++;
void reset() => state = 0;
}
void main() {
final counter = Counter();
counter.increment();
counter.increment();
counter.increment();
print('After 3 increments: ${counter.state}');
counter.reset();
print('After reset: ${counter.state}');
}Snabb kontroll
Ni annoterar en funktion som returnerar Future<List<Product>> med @riverpod. Vilken typ av provider skapar riverpod_generator, och hur använder ni den i en widget?
Sammanfattning
Ni har lärt er hur riverpod_generator tar bort standardkod för providers:
- Lägg till
riverpod_annotation(körning) samtriverpod_generatorochbuild_runner(utveckling), och ettpart '<file>.g.dart';-direktiv. - Annotera en funktion för skrivskyddade eller härledda värden, eller en klass som utökar
_$Nameför tillståndshanterande Notifiers. - Returtypen väljer providern:
T→ synkron,Future<T>→ asynkron (AsyncValue),Stream<T>→ stream. - Lägg till vanliga parametrar efter
refi stället för.family. - Kör
dart run build_runner watchför att generera om vid sparning. - Providers avregistreras automatiskt som standard; använd
@Riverpod(keepAlive: true)för appomfattande singletoner.
Lär dig Dart med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 22
- Lektioner
- 88
Vanliga frågor
Är lektionen ”Kodgenerering med riverpod_generator och @riverpod” gratis?
Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Mobilutveckling med Flutter, inklusive ”Kodgenerering med riverpod_generator och @riverpod”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Mobilutveckling med Flutter innehåller totalt 4 lektioner.
Vad lär jag mig i ”Kodgenerering med riverpod_generator och @riverpod”?
Använd annoteringarna i riverpod_generator för att skapa typsäkra providers utan standardkod. Ni övar på Mobilutveckling med Flutter med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Mobilutveckling med Flutter?
Du behöver inga förkunskaper. Utbildningen i Mobilutveckling med Flutter på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.
Hur lång tid tar lektionen ”Kodgenerering med riverpod_generator och @riverpod”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Mobilutveckling med Flutter-lektionen?
Ja. Varje Mobilutveckling med Flutter-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Från Provider till Riverpod: migrera äldre tillståndshantering
- Kodgenerering med riverpod_generator och @riverpod
- AsyncNotifier- och FutureProvider-datapipelines
- Provider-avgränsning, åsidosättningar och ProviderObserver