初心者でも簡単!Flutter Riverpodによる状態管理ガイド

Flutter

はじめに

Flutterでの状態管理は、シンプルなアプリではsetStateを使うだけで十分ですが、アプリが複雑化するにつれて、効率的に状態を管理する方法が求められます。そんな中で、Riverpodは強力で柔軟な状態管理ソリューションとして注目されています。

本記事では、初心者でもわかりやすいように、Riverpodの基本的な使い方と、それを使った柔軟な状態管理の実装方法を紹介します。


Riverpodとは?

Riverpodは、Providerをベースに開発されたFlutterの状態管理ライブラリで、より安全で柔軟に状態管理が行えるのが特徴です。主な特徴は以下の通りです。

Riverpodの特徴

  • 再利用可能なプロバイダー: グローバルな状態管理だけでなく、個別のコンポーネントごとに状態を管理できます。
  • コンパイル時の安全性: 使用されていないプロバイダーや、誤った参照の検出が可能です。
  • Flutterに依存しない: UIに依存せずにロジックを分離できるため、テストが容易です。

Riverpodの導入手順

Riverpodのインストール

まず、Riverpodをプロジェクトに追加します。pubspec.yamlに以下を追加し、パッケージをインストールします。

YAML
dependencies:
  flutter:
    sdk: flutter
  flutter_riverpod: ^1.0.0

その後、以下のコマンドでパッケージをインストールします。

Bash
flutter pub get

Riverpodの基本的な使い方

Riverpodは、状態管理を行う「プロバイダー」と、状態を提供する「Consumer」で構成されています。プロバイダーは、グローバルな状態を管理し、それをUIコンポーネントに提供します。

プロバイダーの定義

まず、基本的なカウンターアプリを例にして、プロバイダーを定義します。

Dart
import 'package:flutter_riverpod/flutter_riverpod.dart';

// 状態を管理するProviderの定義
// StateProvider<T(型)>((ref) => initialValue(初期値));
final counterProvider = StateProvider<int>((ref) => 0);

StateProviderは、簡単な整数や文字列の状態を管理するために使われます。ここでは、カウントの値を管理しています。

プロバイダーを使った状態の取得と操作

次に、Flutterアプリでこのプロバイダーを使って状態を操作し、UIに反映します。

  • ProviderScope: Riverpodを使用するために、アプリ全体をProviderScopeで包む必要があります。
  • ConsumerWidget: ConsumerWidgetは、Riverpodで提供された状態を簡単にUIに反映できる仕組みを提供します。
  • ref.watch: プロバイダーの状態を監視し、UIに反映します。
  • ref.read: 状態を変更するために使用されます。
Dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'counter_provider.dart';  // 状態管理をインポート

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

// 状態を管理するProviderの定義
final counterProvider = StateProvider<int>((ref) => 0);


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterScreen(),
    );
  }
}

class CounterScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);

    return Scaffold(
      appBar: AppBar(
        title: Text('Riverpod Counter App'),
      ),
      body: Center(
        child: Text('Count: $count', style: TextStyle(fontSize: 40)),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => ref.read(counterProvider.notifier).state++,
        child: Icon(Icons.add),
      ),
    );
  }
}

Riverpodの高度な使い方

FutureProviderを使った非同期処理

Riverpodは、非同期処理にも対応しています。例えば、外部APIからデータを取得する場合には、FutureProviderを使います。

Dart
final weatherProvider = FutureProvider<String>((ref) async {
  // ここでAPIリクエストなどの非同期処理を行う
  await Future.delayed(Duration(seconds: 2));
  return 'Sunny';
});

このFutureProviderは、非同期でデータを取得し、その結果をプロバイダーとして提供します。

非同期データをUIに表示する

次に、この非同期データをUIに表示する例です。

  • AsyncValue.when: 非同期データの取得状態(データ、読み込み中、エラー)に応じてUIを更新します。
Dart
class WeatherScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final weatherAsyncValue = ref.watch(weatherProvider);

    return Scaffold(
      appBar: AppBar(title: Text('Weather App')),
      body: Center(
        child: weatherAsyncValue.when(
          data: (weather) => Text('Weather: $weather'),
          loading: () => CircularProgressIndicator(),
          error: (error, stack) => Text('Error: $error'),
        ),
      ),
    );
  }
}

StateNotifierProviderを使った複雑な状態管理

複雑なビジネスロジックや、複数の状態を管理したい場合には、StateNotifierStateNotifierProviderを使います。

Dart
class CounterNotifier extends StateNotifier<int> {
  CounterNotifier() : super(0);

  void increment() => state++;
}

final counterNotifierProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
  return CounterNotifier();
});

StateNotifierは、状態を保持しつつ、ビジネスロジックを簡単に定義できるクラスです。

抽象化すると下記のようになります。

Dart
class StateNotifierGeneric<T> extends StateNotifier<T> {
  StateNotifierGeneric(T initialValue) : super(initialValue);

  void updateState(T newValue) => state = newValue;
}

final genericNotifierProvider = StateNotifierProvider<StateNotifierGeneric<T>, T>((ref) {
  return StateNotifierGeneric<T>(initialValue);
});

Flutterでのテスト対応

Riverpodはテストのしやすさにも優れています。状態管理のロジックがUIから分離されているため、ユニットテストを簡単に行うことができます。

テストの基本

例えば、カウンター機能のテストを以下のように書くことができます。

Dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:test/test.dart';
import 'counter_notifier.dart';

void main() {
  test('カウンターが正常にインクリメントされるか', () {
    final container = ProviderContainer();
    final counter = container.read(counterNotifierProvider.notifier);

    counter.increment();
    expect(container.read(counterNotifierProvider), 1);
  });
}

まとめ

Riverpodは、Flutterでの状態管理を強力かつ柔軟に行えるツールです。Providerに比べて高い柔軟性を持ちながら、コードの安全性やテストの容易さも向上します。

この記事のポイント:

  • Riverpodの基本的な使い方と導入方法
  • StateProviderを使った簡単なカウンターアプリの実装
  • 非同期処理や複雑なビジネスロジックに対応するFutureProviderStateNotifierProvider
  • テストのしやすさ

Flutterのアプリケーションが複雑になるほど、適切な状態管理は非常に重要です。初心者でもRiverpodを使って簡単に始められるので、この機会にぜひ試してみてください!

コメント

タイトルとURLをコピーしました