riverpod 使い方ガイド

# パッケージ構成
以下の構成でか

![スクリーンショット 2025-02-24 12.56.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3907021/22ebd7f7-6bee-4b02-abf3-9a2d223ccdce.png)

## 必要なパッケージ
```bash
flutter
flutter_hooks
flutter_riverpod
```
## その他に必要なパッケージ
コードを自動で書いてくれたり、色々楽にしてくれるので以下のパッケージも必要になる
```bash
riverpod_annotation
build_runner
riverpod_generator
```

開発時しか使わないものはdevに分けて書く
![スクリーンショット 2025-02-24 13.02.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3907021/d631113f-50d0-493e-bd0b-dd5f35e552ff.png)

```bash
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内にアプリを含めるようにする
```dart
void main() {
  const app = MyApp();
  const scope = ProviderScope(child: app);
  runApp(scope);
}
```
1行にまとめると、

```dart
void main() {
    runApp(ProviderScope(child: MyApp()));
}
```

# 表示させる画面
1. stlでクラスを作成
2. クラス名を変更
3. extendsの後を`StatelessWidget`から`ConsumerWidget`に変更
4. 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の作成
１. コードを作成
```
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;
  }
}
```
２. build_runnerを走らせる

# データの取得方法
build関数内で、
`final data = ref.watch(FugaNotifierProvider);`
を追記することで得られる。

# データの更新方法
`final notifier = ref.read(FugaNotifierProvider.notifier);`
これでnotifier(データの編集者)をゲットする
`notifier.updateState();`
これで先ほど定義したupdate関数を使用する

# メソッドの使い分け
![スクリーンショット 2025-02-24 13.33.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3907021/9e2aa2f4-cf11-4e80-b21c-e22d86709a0e.png)

* listenは変化をトリガーに何かを実行したい時に使用する
* ボタン内などのbuild() {} 直下でない場所では`read`しか使えない

## listenの書き方
```dart
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,
    );
}
```
# 使い分けガイド
![スクリーンショット 2025-02-26 14.25.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3907021/4456da13-bbe5-45ba-8ccd-42ed31d900a0.png)