Flutter開発入門46 hooks_riverpodの使い方:効率的な状態管理を実現

Flutter

はじめに

hooks_riverpodは、Flutterでの状態管理ライブラリRiverpodとフック機能Flutter Hooksを組み合わせた強力なパッケージです。hooks_riverpodを使うことで、状態管理がシンプルになり、状態に応じたUIの更新を直感的に行えるようになります。特に、フックを活用することで、状態の管理やリソースのクリーンアップを簡潔に記述できるため、より効率的にFlutterアプリケーションを開発できます。

この記事では、hooks_riverpodのセットアップから基本的な使い方、実際の利用例まで詳しく解説します。Flutterの開発経験がある方でも、hooks_riverpodを使うことで、状態管理がさらに快適になるでしょう。

hooks_riverpodとは

hooks_riverpodは、Riverpodの状態管理機能とFlutter Hooksのフック機能を統合したパッケージです。Flutter Hooksのコンセプトを取り入れることで、状態管理とUIのロジックをシンプルに記述でき、リソースのクリーンアップなどが簡単になります。

hooks_riverpodの主な特徴

  • フックを活用したシンプルな状態管理:状態の管理やUIの更新がより直感的に行える。
  • リソースのクリーンアップが簡単:フックによって、不要になったリソースを自動的に解放できる。
  • Riverpodのすべての機能に対応Riverpodのプロバイダや依存関係管理をそのまま利用可能。

なぜhooks_riverpodを使うべきか?

  1. UIロジックを簡潔に記述:状態管理とUIロジックがフックによってシンプルにまとめられます。
  2. 効率的なリソース管理:ウィジェットのライフサイクルに応じてリソースを自動的にクリーンアップ。
  3. パフォーマンス向上:不要な再レンダリングを防ぐことで、アプリケーションのパフォーマンスが向上します。

hooks_riverpodのセットアップ

まず、pubspec.yamlhooks_riverpodパッケージを追加します。

dependencies:
  flutter:
    sdk: flutter
  hooks_riverpod: ^2.5.1

次に、依存関係をインストールします。

flutter pub get

hooks_riverpodの基本的な使い方

1. ProviderScopeでアプリを包む

まず、hooks_riverpodを使用する際は、アプリケーション全体をProviderScopeで包む必要があります。これにより、すべてのプロバイダがアプリ全体で利用できるようになります。

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

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

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

2. ref.watchを使ったプロバイダの状態監視

hooks_riverpodの基本的な状態管理は、プロバイダを使って行います。useProviderは廃止され、代わりにWidgetRefを使ってref.watchで状態を監視するのが現在の標準です。

例:シンプルな文字列プロバイダ
final helloWorldProvider = Provider<String>((ref) => 'Hello, World!');

class HomeScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // WidgetRefを使ってプロバイダの状態を監視
    final value = ref.read(helloWorldProvider);

    return Scaffold(
      appBar: AppBar(title: Text('Riverpod with Hooks')),
      body: Center(child: Text(value)),
    );
  }
}

3. StateProviderを使った状態変更

StateProviderを使えば、カウンターのような状態を簡単に管理できます。WidgetRefを使って、ref.watchref.readを活用し、状態の監視や変更を行います。

例:カウンターアプリの実装
final counterProvider = StateProvider<int>((ref) => 0);

class HomeScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // カウンターの値を監視
    final count = ref.watch(counterProvider);

    return Scaffold(
      appBar: AppBar(title: Text('Counter Example')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Count: $count', style: TextStyle(fontSize: 40)),
            SizedBox(height: 20),
            ElevatedButton(
              // カウンターの値を変更
              onPressed: () => ref.read(counterProvider.notifier).state++,
              child: Text('Increment'),
            ),
          ],
        ),
      ),
    );
  }
}

解説

  • ref.watch(counterProvider):カウンターの現在の値を取得して監視します。状態が変更されるたびにUIがリビルドされます。
  • ref.read(counterProvider.notifier):状態を直接操作して変更するために使用します。

非同期処理とFutureProvider

非同期処理を行う場合は、FutureProviderを使います。以下は、APIなどのデータを非同期で取得する例です。

final dataProvider = FutureProvider<String>((ref) async {
  await Future.delayed(Duration(seconds: 2));
  return 'Hello from Future!';
});

class HomeScreen extends HookWidget {
  @override
  Widget build(BuildContext context) {
    // 非同期データを監視
    final asyncValue = ref.watch(dataProvider);

    return Scaffold(
      appBar: AppBar(title: Text('FutureProvider Example')),
      body: Center(
        child: asyncValue.when(
          data: (value) => Text(value),
          loading: () => CircularProgressIndicator(),
          error: (err, stack) => Text('Error: $err'),
        ),
      ),
    );
  }
}

解説

  • FutureProvider:非同期データを提供するプロバイダで、APIリクエストやデータベース操作などに使われます。
  • asyncValue.when:非同期処理の状態に応じて、データ表示、ローディングインジケーター、エラーメッセージの表示を切り替えます。

Riverpodのベストプラクティス

  1. ProviderScopeを適切に使用
    • すべてのプロバイダはProviderScope内で管理されるため、これをアプリのルートに配置することで、すべてのプロバイダが適切に管理されます。
  2. ref.watchref.readの使い分け
    • ref.watch:プロバイダの値を監視し、変更があるたびにUIを再レンダリングします。
    • ref.read:値を一度取得するだけ、または値を更新する場合に使います(再レンダリングは行われません)。
  3. 非同期データの管理
    • FutureProviderStreamProviderを使って非同期データの状態(ロード中、エラー、成功)を適切に処理することが、ユーザーフレンドリーなUIを提供する鍵です。

まとめ

hooks_riverpodを活用することで、Flutterアプリケーションの状態管理が簡単になり、UIロジックがシンプルに記述できます。特に、WidgetRefを使ったref.watchによる状態管理は直感的で、プロジェクトの複雑度に応じてスケーラブルに使えます。この記事を参考に、hooks_riverpodをマスターし、Flutter開発をさらに効率的に行いましょう。

コメント