| name | description | metadata | ||||
|---|---|---|---|---|---|---|
Riverpod |
Riverpodをスムーズに使いこなすためのスキル |
|
Configures and implements the Riverpod reactive caching and data-binding framework for Dart and Flutter applications. Handles dependency resolution, provider generation, state consumption, and enforces strict static analysis rules via riverpod_lint to ensure predictable, scalable, and testable asynchronous state management.
Before implementing Riverpod, determine the target architecture using the following logic:
- Target Platform: Is the application pure Dart or Flutter?
- Hooks: Does the application use
flutter_hooks? (If yes, requireshooks_riverpod). - Code Generation: Is code generation preferred? (Highly recommended; requires
riverpod_annotationandriverpod_generator).
-
Determine Environment and Architecture STOP AND ASK THE USER: "Please specify your environment preferences for Riverpod: 1. Flutter or pure Dart? 2. Do you want to use
flutter_hooks? 3. Do you want to use code generation (riverpod_generator)?" -
Configure Dependencies Based on the user's response, inject the exact dependencies into
pubspec.yaml.For Flutter + Code Gen (Standard Recommended):
dependencies: flutter: sdk: flutter flutter_riverpod: ^3.2.1 riverpod_annotation: ^4.0.2 dev_dependencies: build_runner: riverpod_generator: ^4.0.3
For Flutter + Hooks + Code Gen:
dependencies: flutter: sdk: flutter hooks_riverpod: ^3.2.1 flutter_hooks: riverpod_annotation: ^4.0.2 dev_dependencies: build_runner: riverpod_generator: ^4.0.3
-
Enable Strict Linting Configure
riverpod_lintto enforce framework rules. Create or updateanalysis_options.yamlat the project root:analyzer: plugins: - custom_lint dependencies: custom_lint: riverpod_lint: ^3.1.3
-
Initialize the Root Scope Initialize the state container at the entry point of the application.
For Flutter:
import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; void main() { runApp( const ProviderScope( child: MyApp(), ), ); }
For Pure Dart:
import 'package:riverpod/riverpod.dart'; void main() { final container = ProviderContainer(); // Use container.read(...) to access providers }
-
Define Providers Implement providers using the chosen architecture.
Using Code Generation (Functional):
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; part 'activity_provider.g.dart'; @riverpod Future<String> boredSuggestion(Ref ref) async { final response = await http.get( Uri.https('boredapi.com', '/api/activity'), ); final json = jsonDecode(response.body); return json['activity']! as String; }
Using Code Generation (Class-based Notifier):
import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'counter_provider.g.dart'; @riverpod class Counter extends _$Counter { @override int build() => 0; void increment() => state++; }
-
Consume Providers in the UI Bind the UI to the providers and handle asynchronous states gracefully.
Using
ConsumerWidget:class Home extends ConsumerWidget { const Home({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final suggestion = ref.watch(boredSuggestionProvider); return switch (suggestion) { AsyncData(:final value) => Text('Data: $value'), AsyncError(:final error) => Text('Error: $error'), _ => const CircularProgressIndicator(), }; } }
Using
HookConsumerWidget(if hooks are enabled):class Home extends HookConsumerWidget { const Home({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final counter = useState(0); final suggestion = ref.watch(boredSuggestionProvider); return Text('Local: ${counter.value}, Async: ${suggestion.valueOrNull}'); } }
-
Validate and Fix Review the generated code against the
riverpod_lintrules. If any constraints (listed below) are violated, immediately refactor the code to comply.
- Scope Requirement: Flutter applications MUST have a
ProviderScopeat the root of the widget tree. - No BuildContext in Providers: Providers and Notifiers MUST NOT receive or interact with
BuildContext. - Notifier Encapsulation:
NotifierandAsyncNotifierclasses MUST NOT expose public properties or getters outside of thestateproperty. All state mutations must happen via methods that updatestate. - Notifier Inheritance: Classes annotated with
@riverpodMUST extend_$ClassNameand MUST implement abuild()method. - Functional Ref Naming: Functional providers MUST receive a
Refobject as their first positional parameter, and it MUST be namedref. - Parameter Equality: Provider parameters MUST have a consistent
==operator. Use constant objects or override==andhashCodefor custom parameter classes. - KeepAlive Dependencies: A provider marked with
keepAlive: trueMUST NOT depend on a provider that is auto-disposed (non-keepAlive). - Dispose Safety: Do NOT use
ref.read()orref.watch()inside thedispose()method of aConsumerState. - Scoped Dependencies: If a provider depends on other scoped providers, it MUST explicitly list them using
@Riverpod(dependencies: [otherProvider]). - Cross-Notifier State Access: Notifiers MUST NOT access the protected properties (
.state,.future,.ref) of other notifiers. Use exposed public methods for cross-notifier interactions. - Nullable Async Patterns: Do NOT use the pattern
AsyncValue(:final value?)if the underlying data type is nullable. UseAsyncValue(:final value, hasValue: true)instead.