パッケージ構成
以下の構成でか
必要なパッケージ
flutter
flutter_hooks
flutter_riverpod
その他に必要なパッケージ
コードを自動で書いてくれたり、色々楽にしてくれるので以下のパッケージも必要になる
riverpod_annotation
build_runner
riverpod_generator
flutter pub add flutter_hooks
flutter pub add flutter_riverpod
flutter pub add riverpod_annotation
flutter pub add hooks_riverpod
flutter pub add --dev build_runner
flutter pub add --dev riverpod_generator
下準備
main.dart
のmain関数を以下のように編集して、scope内にアプリを含めるようにする
void main() {
const app = MyApp();
const scope = ProviderScope(child: app);
runApp(scope);
}
1行にまとめると、
void main() {
runApp(ProviderScope(child: MyApp()));
}
表示させる画面
- stlでクラスを作成
- クラス名を変更
- extendsの後を
StatelessWidget
からConsumerWidget
に変更 - buildかっこ内に
ref
を追加
完成コード
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class Hogehoge extends ConsumerWidget {
const Hogehoge({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return const Placeholder();
}
}
Notifierとproviderの作成
1. コードを作成
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'hogehoge.g.dart';
@riverpod
class FugaNotifier extends _$FugaNotifier {
@override
int build() {
// 最初のデータ
return 0;
}
// データを変更する関数
void updateState() {
// 変更前のデータ
final oldState = state;
// 変更後のデータ
final newState = oldState + 1;
// データを上書き
state = newState;
}
}
2. build_runnerを走らせる
データの取得方法
build関数内で、
final data = ref.watch(FugaNotifierProvider);
を追記することで得られる。
データの更新方法
final notifier = ref.read(FugaNotifierProvider.notifier);
これでnotifier(データの編集者)をゲットする
notifier.updateState();
これで先ほど定義したupdate関数を使用する
メソッドの使い分け
- listenは変化をトリガーに何かを実行したい時に使用する
- ボタン内などのbuild() {} 直下でない場所では
read
しか使えない
listenの書き方
ref.listen(
s1NotifierProvider,
(oldState, newState) {
// スナックバーを表示
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('S1データが変更されました'),
),
);
},
);
AsyncValueの使い方
以下のように状態を場合分けできr
final hoge = ref.watch(FugaNotifierProvider);
final Widget = hoge.when(
loading: () => const Text('準備中'),
error: (e, s) => Text('エラー $e'),
data: (d) => Text(d),
);
basic providerへの変換方法例
※basic providerはメソッドを持っていないクラスに適応する。
変更前
// private navigators
import ...
final _rootNavigatorKey = GlobalKey<NavigatorState>();
class AppRouter {
static final goRouter = GoRouter(
initialLocation: AppRoute.tasks.path,
navigatorKey: _rootNavigatorKey,
debugLogDiagnostics: true,
routes: [
...
],
),
],
);
}
変更後
import ...
import 'package:go_router/go_router.dart';
part 'app_router.g.dart'; <-追加 (このファイル名に'.g.'を追加したもの)
final _rootNavigatorKey = GlobalKey<NavigatorState>();
@riverpod <-追加
GoRouter appRouter(ref) { <-変更 (GoRouter型で定義して、クラス名の頭を小文字にする)
return GoRouter( <-変更 (変数に代入ではなく、returnするようにする)
initialLocation: AppRoute.tasks.path,
navigatorKey: _rootNavigatorKey,
debugLogDiagnostics: true,
routes: [
...
],
),
],
);
}
使う側は以下のように変更する
変更前
Widget build(BuildContext context) {
return MaterialApp.router(
// theme: ThemeData(appBarTheme: AppBarTheme(color: Colors.pink)),
routerConfig: AppRouter.goRouter,
debugShowCheckedModeBanner: false,
);
}
変更後
Widget build(BuildContext context, WidgetRef ref) {
final appRouter = ref.watch(appRouterProvider);
return MaterialApp.router(
// theme: ThemeData(appBarTheme: AppBarTheme(color: Colors.pink)),
routerConfig: appRouter,
debugShowCheckedModeBanner: false,
);
}