Dart only で Riverpodを使う方法

## 概要

FlutterにおけるRiverpodの使い方を解説している記事はいろいろ見かけるが、Dart onlyにおけるRiverpodの使い方を解説している記事がなかったので書いてみる。


## インストール

```yml:pubspec.yaml
dependencies:
  # ....
  riverpod: ^2.1.3
  riverpod_annotation: ^1.1.1

dev_dependencies:
  # ....
  build_runner:
  riverpod_generator: ^1.1.1
```

## provider自動生成の準備

以下をターミナルで実行する。

### プロバイダー追加時に毎回実行する場合
```bash
dart pub run build_runner build
```

### コードの変更を自動で検知し、その都度buildを走らせたい場合
```bash
dart pub run build_runner watch
```
こちらの方が楽。

## riverpod_annotationを用いたproviderの作り方

```dart:main.dart
import 'package:riverpod/riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'main.g.dart';

@riverpod
String helloWorld(HelloWorldRef ref) {
  return 'Hello world';
}
```

```dart:main.dart
import 'package:riverpod/riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'main.g.dart';

@riverpod
class BoolStateManager extends _$BoolStateManager {
  @override
  bool build() {
    return false;
  }

  void toggle() {
    state = !state;
  }
}
```


## providerのstateを読む

```dart:main.dart
import 'package:riverpod/riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'main.g.dart';

@riverpod
String helloWorld(HelloWorldRef ref) {
  return 'Hello world';
}

Future<void> main() async {
    final container = ProviderContainer();
    
    final value = container.read(helloWorldProvider);
    
    print(value);
}
```

```dart:main.dart
import 'package:riverpod/riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'main.g.dart';

@riverpod
class BoolStateManager extends _$BoolStateManager {
  @override
  bool build() {
    return false;
  }

  void toggle() {
    state = !state;
  }
}

Future<void> main() async {
    final container = ProviderContainer();
    
    final value = container.read(boolStateManagerProvider);
    
    print(value);
}
```


## providerのstateを更新する


```dart:main.dart
import 'package:riverpod/riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'main.g.dart';

@riverpod
class BoolStateManager extends _$BoolStateManager {
  @override
  bool build() {
    return false;
  }

  void toggle() {
    state = !state;
  }
}

Future<void> main() async {
    final container = ProviderContainer();
    
    final value = container.read(boolStateManagerProvider);
    
    print(value);

    // ここで更新
    container.read(boolStateManagerProvider.notifier).toggle();    

    final toggledValue = container.read(boolStateManagerProvider);
    
    print(toggledValue);
}
```

## providerのstateの変更を検知する


```dart:main.dart
import 'package:riverpod/riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'main.g.dart';

@riverpod
class BoolStateManager extends _$BoolStateManager {
  @override
  bool build() {
    return false;
  }

  void toggle() {
    state = !state;
  }
}

class BoolListener extends ProviderObserver {
  @override
  void didUpdateProvider(
    ProviderBase<dynamic> provider,
    Object? previousValue,
    Object? newValue,
    ProviderContainer container,
  ) {
    print('''
{
  "provider": "${provider.name ?? provider.runtimeType}",
  "newValue": "$newValue"
}''');
  }
}

Future<void> main() async {
  // observersにBoolListenerを追加
  final container = ProviderContainer(observers: [BoolListener()]);
    
  final value = container.read(boolStateManagerProvider);
    
  print(value);

  // ここで更新すると、BoolListener#didUpdateProvider が呼ばれる
  container.read(boolStateManagerProvider.notifier).toggle();    

  final toggledValue = container.read(boolStateManagerProvider);
    
  print(toggledValue);
}
```


## 参考文献

https://docs-v2.riverpod.dev/docs/getting_started

https://docs-v2.riverpod.dev/docs/concepts/provider_observer

https://torikatsu923.hatenablog.com/entry/2022/11/14/030055