121
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

RiverpodとFlutter Hooksを使う、はじめの一歩

はじめに

この記事では、RiverpodとFlutter Hooksを使う、はじめの一歩として、
カウンターアプリを作ってみようと思います。

今回作成したコードはこちらのリポジトリに公開しています。
https://github.com/karamage/riverpod_flutterhooks_example

スクリーンショット 2020-08-01 14.34.35.png

Flutterの状態管理パターン

みなさん、Flutterの状態管理パターンは、何を使っていますでしょうか?

Flutterの状態管理パターンはいっぱいあります。
大すぎですw

  • StatefulWidget
  • Redux
  • BLoC(Stream/InheritedWidget) + Provider
  • ChangeNotifier + Provider
  • StateNotifier + freezed + Provider
  • StateNotifier + Flutter Hooks + Riverpod 【new】

私は、これまでは「StateNotifier + freezed + Provider」を主に使っていました。

「StateNotifier + freezed + Provider」の使い方については、以下に記事を書きました。
https://qiita.com/karamage/items/4b1aff984b1af7541b73

新たなパターン登場

そんな今日この頃ですが、状態管理パターンにキラボシのごとく輝く新星が現れました。

「RiverpodとFlutter Hooks」です。

最近、Flutter界隈では、RiverpodとFlutter Hooksが話題です。

@mono0926 さんがツイッターで、Riverpodの発言をしているのをよく拝見します。

そこで、私もいっちょやってみようかなと思いました。

ざざっと、RiverpodとFlutterHooksを使ってカウンターアプリを作ってみましたので、当記事にまとめます。

Riverpodとは

Providerの作者による、Providerの進化版です。

Provider, but different

Riverpod公式ページ
https://riverpod.dev
スクリーンショット 2020-08-01 14.36.53.png

「Providerってなに?」って方は、以下のページが詳しいです。

FlutterのProviderパッケージを使いこなす
https://itome.team/blog/2019/12/flutter-advent-calendar-day7/

もともと使いやすかった「Provider」をさらに強化したのが「Riverpod」なのですね!

Riverpodの良いところ

  • Flutterに依存しなくなった(Pure Dart)

    • ProviderがInheritedWidgetをラップしたものだった。
    • RiverpodはInheritedWidgetを使わずゼロから構築した。
    • Providerから状態を読み込む際、BuildContextが必要なくなった。
  • コンパイル時にエラーを検知できる

    • Providerでは実行時にしかエラーが検知できなかった。
    • よくあったのが、Providerから状態を読み出そうとして、「Providerが見つからない」エラー
  • 同じ型のProviderを複数配信できる

  • ProviderをPrivateにできる

  • ProviderをWidget Tree限定でなく、Model/Domain Logic/Repositoryどこでも利用できる

  • グローバル変数としてProviderを宣言できるようになった

  • 使われていないProviderの状態をdisposeできる

  • Computedで、Providerの状態を使って計算した値を状態として持てる。

  • 他にも、Family、AutoDisposeProviderなどの新機能多数

  • Hooks的な使い方も可能(ゆえにHooks APIとの相性がよい)

    • Hooksなしでも使える

※ただし、Flutter公式はHooksを肯定的には捉えていない。今後の動向に注目。

Riverpodの悪いところ

  • まだまだ開発段階
  • Hooks推しがどうなるか不明。(Flutter公式は否定的
  • これから破壊的な変更が入りそう
  • プロダクトに組み込むにはまだ早い感じ
    • stableされるまで待とう。(将来的には、Flutter標準に取り込まれるのを願う)

Flutter Hooks とは

「React Hooks」のFlutter版みたいなイメージです。

参考:5分でわかるReact Hooks
https://qiita.com/Mitsuzara/items/98d1bc4a83265a764084

https://riverpod.dev
Riverpodの公式ページを見る限り、RiverpodとFlutter Hooksはセットで使うのが、作者の推しみたいです。
RiverpodはFlutter Hooksを外しても利用できます。

カウンターアプリを作ってみよう

Riverpod と Flutter Hooks と StateNotifierインストール

pubspec.yaml
environment:
  sdk: ">=2.7.0 <3.0.0"
  flutter: ">= 1.17.0"

dependencies:
  flutter:
    sdk: flutter
  flutter_hooks: ^0.11.0
  hooks_riverpod: ^0.5.1
  state_notifier: ^0.5.0

pubspec.yamlに上記のように書いて、ターミナルで「flutter pub get」しましょう。

flutter pub get

これでインストールは完了です。

それでは、コードを書いていきましょう。

lib/main.dart
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:state_notifier/state_notifier.dart';

final counterProvider = StateNotifierProvider((_) => Counter());

class Counter extends StateNotifier<int> {
  Counter() : super(0);
  void increment() => state++;
}

void main() {
  runApp(
    ProviderScope(
      child: CounterApp(),
    ),
  );
}

// Note: CounterApp is a HookWidget, from flutter_hooks.
class CounterApp extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final state = useProvider(counterProvider.state);
    final counter = useProvider(counterProvider);

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('CounterApp')),
        body: Center(
          child: Text(state.toString()),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed:() => counter.increment(),
          child: Icon(Icons.add),
        ), // This trailing comma makes auto-formatting nicer for build methods.
      ),
    );
  }
}

めちゃくちゃコードがすっきり書けて感動。

実行して、「+」を押すと数字がカウントアップすると思います。
スクリーンショット 2020-08-01 14.34.35.png

コードの説明

グローバルにProviderを宣言することができる

final counterProvider = StateNotifierProvider((_) => Counter());

ProviderだとWidget Treeのrootのほうで、Providerを作成していたと思います。
Riverpodでは、グローバルに、Widget Treeに縛られることなく、Providerの作成が可能です。

Providerにスコープを設定できる

    ProviderScope(
      child: CounterApp(),
    ),

ProviderScopeを使えば、Providerにアクセスできる階層をコントロールすることができます。

Hooksをつかうためには、HookWidgetを継承する

class CounterApp extends HookWidget {

将来的にはclassではなく、「React Hooks」と同じように関数で書けるようになるといいですね。
そのためにもFlutte公式がHooksを認めてもらえるといいなと思います。

状態を読み込むには、useProviderを使う

final state = useProvider(counterProvider.state);

めっちゃ簡単でシンプルですね。
BuildContextが必要なくなったのが良い!

まとめ

  • Riverpodめっちゃ良い。Providerから正当進化している。使わない理由がない。
  • 今後は、Providerではなく、Riverpodを使っていきたい。
  • しかしながら、Hooksがどうなるかわからないので、もうしばらくは様子見かなぁ。
  • Hooksを外して使うのが良いかも。
  • まずは個人アプリで採用してみようと思います。

最後までお読みいただき、ありがとうございました。

今回作成したコードはこちらのリポジトリに公開しています。
https://github.com/karamage/riverpod_flutterhooks_example

参考リンク

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
121
Help us understand the problem. What are the problem?