Chapter 01

Providerの使い方

JboyHashimoto
JboyHashimoto
2023.03.27に更新

Riverpod2.0の公式ページ
https://docs-v2.riverpod.dev/docs/introduction

Flutterの状態管理を行うパッケージといば、Riverpod以外ないのではというぐらいに、人気があります。そんな人気のパッケージについて学ぼうと、本を出版することにしました。
そもそもどんな目的で使うのか?

わかりやすく説明すると、画面とロジックを分けることですね。Riverpodのいいところはどこからでも値を渡すことができるところですね。
最近は、ジェネレーターなるものが出てきて、以前よりも難しくなってきた気がします😅
まずは、Providerを使ってみましょう。これはどんなものかというと、ただの定数ですね。変更しない値を入れておきます。

RiverpodのProviderとはどんなものか?

  • Provider ・・・ 定数
  • StateProvider ・・・ 変数
  • StateNotifierProvider・・・変数 + メソッド
  • FutureProvider・・・Future版(あとでデータを取ってきてから参照するなど)
  • StreamProvider・・・Stream版(snapshotなどを利用してFirebaseなどからデータをとってくるのよく使われる)
  • ChangeNotifierProvider・・・ChangeNotifierを使う

使用するユースケース

Riverpod Providerを使用すると、アプリケーション内のデータを管理したり、依存関係を解決したりすることができます。

例えば、あるアプリケーション内でデータベースとAPIを使用している場合、Riverpod Providerを使用することで、データベースやAPIへのアクセスを行うための依存関係を解決したり、アプリケーション内のデータを管理したりすることができます。

また、アプリケーション内でサービスを使用している場合も、Riverpod Providerを使用することで、サービスへの依存関係を解決したり、複数のサービスを管理したりすることができます。

Objectboxのインスタンス化に使用した例

// Objectboxをインスタンス化して、DBにアクセスできるようにするProvider.
final objectboxProvider = Provider((ref) => objectbox.store.box<User>());

Firestoreへアクセスするためのクラスをインスタンス化した例

// Firestoreを使うためのProvider
final firebaseProvider =
    Provider<FirebaseFirestore>((ref) => FirebaseFirestore.instance);

公式を参考に新しい機能のジェネレーターを試してみましたが、うまくいかない?
pub.devの方のコマンドを実行するとうまくいった?
https://docs-v2.riverpod.dev/docs/getting_started

コマンドを実行するには、ビルドランナーのパッケージも必要なので、追加してください。
https://pub.dev/packages/build_runner


import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'hello_provider.g.dart';// g.dartの前のファイル名は今見ているファイル名と同じにする

// We create a "provider", which will store a value (here "Hello world").
// By using a provider, this allows us to mock/override the value exposed.

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

class HelloProvider extends ConsumerWidget {
  const HelloProvider({Key? key}) : super(key: key);

  
  Widget build(BuildContext context, WidgetRef ref) {
    final String value = ref.watch(helloWorldProvider);

    return Scaffold(
      appBar: AppBar(
        title: const Text('Provider'),
      ),
      body: Center(
        child: Text(value),
      ),
    );
  }
}

雛形となるコードを書いたら、コマンドを実行してファイルを自動生成する。

dart pub run build_runner watch

自動生成されたファイル
Hello Worldを表示するだけですけど、慣れないと難しいですね。

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'hello_provider.dart';

// **************************************************************************
// RiverpodGenerator
// **************************************************************************

// ignore_for_file: avoid_private_typedef_functions, non_constant_identifier_names, subtype_of_sealed_class, invalid_use_of_internal_member, unused_element, constant_identifier_names, unnecessary_raw_strings, library_private_types_in_public_api

/// Copied from Dart SDK
class _SystemHash {
  _SystemHash._();

  static int combine(int hash, int value) {
    // ignore: parameter_assignments
    hash = 0x1fffffff & (hash + value);
    // ignore: parameter_assignments
    hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
    return hash ^ (hash >> 6);
  }

  static int finish(int hash) {
    // ignore: parameter_assignments
    hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
    // ignore: parameter_assignments
    hash = hash ^ (hash >> 11);
    return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
  }
}

String _$helloWorldHash() => r'8bbe6cff2b7b1f4e1f7be3d1820da793259f7bfc';

/// See also [helloWorld].
final helloWorldProvider = AutoDisposeProvider<String>(
  helloWorld,
  name: r'helloWorldProvider',
  debugGetCreateSourceHash:
      const bool.fromEnvironment('dart.vm.product') ? null : _$helloWorldHash,
);
typedef HelloWorldRef = AutoDisposeProviderRef<String>;