Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Try Riverpod2.0

Kuroneko-mayuge
September 12, 2023

Try Riverpod2.0

Try Riverpod2.0

Kuroneko-mayuge

September 12, 2023
Tweet

More Decks by Kuroneko-mayuge

Other Decks in Business

Transcript

  1. About Me Ryo Kuroki 株式会社Relic, 2023 6 月中途入社 Flutter 歴

    業務では約3 ヶ月 個人開発で約1 年 IT エンジニア歴 約3 年 主にFE Relic では「coordimate 」というモバイルアプリサービスの FE 開発とPDM っぽいことをしています EXPERIENCE
  2. v2.0 以降のProvider の種類 Provider 概要 NotifierProvider v2.0から登場。メインの機能 AsyncNotifierProvider v2.0から登場。FutureProviderではできない状態の変更が可能 Provider

    これまで通り。Repositoryなどの状態を持たないケースで利用 StateProvider NotifierProviderより非常に単純な場合。レガシー? StateNotifierProvider NotifierProviderを推奨と明記されている FutureProvider AsyncNotifierProviderを使うほどでもない、状態の変更を伴わない単純なユースケース StreamProvider FutureProviderのStream版 ChangeNotifier 元々非推奨。ChangeNotifierProviderからの置き換えの手始めに最も簡単。
  3. 初期値の設定を わかりやすく実装しやすい ここで、 ref.watch(otherProvider) などと、 他のprovider を参照できる 状態を変更するメソッドを UI に公開する

    code generation によって Notifier とNotifierProvider が生成され る @riverpod class Todos extends _$Todos { @override List<Todo> build() { return []; } void addTodo(Todo todo) { state = [...state, todo]; } } final todosProvider = NotifierProvider<TodosNotifier, List<Todo>>(() { return TodosNotifier(); });
  4. // Riverpod 1系 final fetchUserProvider = FutureProvider.autoDispose.family<User, int>((ref, userId) async

    { final json = await http.get('api/user/$userId'); return User.fromJson(json); }); // Riverpod 2系 @riverpod Future<User> fetchUser(FetchUserRef ref, {required int userId, required int page}) async { final json = await http.get('api/user/$userId/$page'); return User.fromJson(json); } autoDispose がデフォルトでON になった ( 破棄せず保持したい時はkeepAlive:true と明示する) 引数を1 個しか設定できなかったのが、任意で追加できるようになった
  5. // Riverpod導入前はMultiProviderを利用していたので、削除 MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => AppUser()), ChangeNotifierProvider(create:

    (_) => EtcProvider()) MultiProvider の部分を削除 自分の場合は、runApp の配下をProviderScope で囲んだ runApp( child: const ProviderScope( child: MyApp(), )) 導入前 導入後
  6. // providerパッケージのChangeNotifierProviderを利用していた class AppUser extends ChangeNotifier { /// ユーザーIDの設定や、ユーザー名の変更メソッドなど }

    とりあえずRiverpod のChangeNotifierProvider を利用して、コード変更量の少なさを重視 ※ChangeNotifierProvider が公式に非推奨であることと、その理由は理解する import 'package:flutter_riverpod/flutter_riverpod.dart'; // AppUserクラスは変更なし final appUserNotifierProvider = ChangeNotifierProvider<AppUserNotifier>((ref) { return AppUserNotifier(); }) 導入前 導入後
  7. // class UserProfilePage extends StatefulWidget { class UserProfilePage extends ConsumerStatefulWidget

    { とりあえずStatefulWidget→ConsumerStatefulWidget に変更 ※Consumer,ConsumerWidget よりも再ビルドのコストが大きくなりそうなことを理解する // String userId = Provider.of<AppUser>(context).userId; String userId = ref.watch(appUserNotifierProvider).userId; // Provider.of<AppUser>(context, listen: false).setAppUser(id); ref.read(appUserNotifierProvider.notifier).setAppUser(id); ステートの値をUI 側で監視、変更する方法はあまり変わらない Riverpod1.0 を使っていた場合は特に変更なし
  8. import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'note_list_provider.g.dart'; @riverpod class NoteList extends _$NoteList {

    @override // buildの引数に指定すると、generatorの方で認識される FutureOr<List<Note?>> build(String userId) async { return Future.value(_fetchNotes(userId)); } Future<List<Note?>> _fetchNotes(String userId) async { list = []; // Firestoreからの取得などの非同期処理でlistを更新 // AsyncValue.data()で非同期処理が成功した時のデータが取得できるので、状態を更新 state = AsyncValue.data(list); return list; } Future<List<ExchangeNote?>> reloadNotes(String userId) async { // AsyncLoading()を挟めば、Consumer側でLoading画面を表示できる state = const AsyncLoading(); await Future.delayed(const Duration(seconds: 1)); return _fetchNotes(userId); } }
  9. flutter pub run build_runner build ターミナルでコマンド実行すると、自動で認識してAsyncNotifier とそのProvider が生成される final myNotes

    = ref.watch(noteListProvider(userId)) myNotes.when( loading: () => WidgetUtils().createProgressIndicator(), error: (error, stack) => Center( child: Text('エラーが発生しました\n$error'), ), data: (myNotes) { // List表示とか } UI 側での使い方はRiverpod1 系と変わらない FutureValue を監視して、Loading 、エラー時、成功時の値を直感的に実装できる