久々に見直してたら、@riverpod
を使って簡潔にProviderが書けるようになっている。
Stateとかを書かなくて良くなったけど、いろいろ忘れているので、
再度入門したときの備忘録(*´ω`*)
参照した公式ドキュメントはこのあたり。
- hooks_riverpod | Flutter Package
- flutter_hooks | Flutter Package
- Riverpod
- Flutter Riverpod Snippets - Visual Studio Marketplace
インストール
$ fvm flutter pub add flutter_hooks hooks_riverpod riverpod_annotation $ fvm flutter pub add -d riverpod_generator build_runner $ fvm flutter pub add -d custom_lint riverpod_lint
pubspec.yaml
はこんな感じ。
# pubspec.yaml environment: sdk: ">=3.0.5 <4.0.0" dependencies: flutter: sdk: flutter freezed_annotation: ^2.2.0 flutter_hooks: hooks_riverpod: ^2.3.6 riverpod_annotation: ^2.1.1 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0 freezed: ^2.3.5 build_runner: ^2.4.6 json_serializable: ^6.7.1 riverpod_generator: ^2.2.3
analysis_options.yaml
の設定
# analysis_options.yaml analyzer: plugins: - custom_lint
Widgetの種類
- Flutterの基本Widget
- StatelessWidget ... 状態なし
- StatefulWidget ... 状態あり
- HookConsumerWidget from hooks_riverpod
- = ConsumerWidget + HookWidget
- HookWidget = hookが使えるStatelessWidget from flutter_hooks
- ConsumerWidget = providerが使えるStatelessWidget from flutter_riverpod
- 基本はこれを使う
- = ConsumerWidget + HookWidget
- StatefulHookConsumerWidget from hooks_riverpod
- StatefulWidgetのライフサイクルメソッドが使えるHookConsumerWidget
@riverpod
を使った書き方
@riverpod
を使って簡潔にProviderが書けるようになっている。
// providers.dart import "package:riverpod_annotation/riverpod_annotation.dart"; part 'providers.g.dart'; // data-model class Todo { Todo(this.description, this.isCompleted); final bool isCompleted; final String description; } // stateをもつProvider // (= NotifierProvider.autoDispose/AutoDisposeNotifier) // todosProviderを自動生成 @riverpod class Todos extends _$Todos { @override List<Todo> build() { return []; // stateの初期値 } void addTodo(Todo todo) { state = [...state, todo]; } } // stateを持たないデータを加工するだけのProvider // (= Provider.autoDispose) // completedTodosProviderを自動生成 @riverpod List<Todo> completedTodos(CompletedTodosRef ref) { final todos = ref.watch(todosProvider); // we return only the completed todos return todos.where((todo) => todo.isCompleted).toList(); }
あとは、build_runner
を実行すると、自動生成してくれる。
$ fvm flutter pub run build_runner build --delete-conflicting-outputs $ fvm flutter pub run build_runner watch --delete-conflicting-outputs # うまくいかないときには、cleanしてから再度buildするとよい $ fvm flutter pub run build_runner clean $ fvm flutter pub run build_runner build --delete-conflicting-outputs
自動生成できたら、こんな感じでHookConsumerWidgetから呼び出せる。
import 'providers.dart'; class HomePage extends HookConsumerWidget { const HomePage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final provider = ref.watch(completedTodosProvider); // ... } }
書き方の規則
規則的にはこんな感じ。
<filename>
、<ClassName>
、<functionName>
は、
それぞれ合わせないと自動生成に失敗する。
// <filename>.dart import "package:riverpod_annotation/riverpod_annotation.dart"; part '<filename>.g.dart'; // <className>Providerを生成 @riverpod class <ClassName> extends _$<ClassName> { @override List<T> build() { return // ... } } // <functionName>Providerを生成 @riverpod List<T> <functionName>(<FunctionName>Ref ref) { return // ... }
class/functionの他に、return typeで使われるProviderが異なる。
他のパターン
他の書き方は以下のMigrate from non-code-generation variant
に書いてあるので、
一読するのをおすすめ。
また、左のメニューにあるThird party examples
もかなり増えているので、
とても参考になった。
以前よりもかなり簡潔に書けるようになっていてすごい(*´ω`*)