10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

freezed、stateNotifier、Riverpodで状態管理してみた。

Last updated at Posted at 2021-02-01

初めに

Providerの作者が去年riverpodという状態管理法を作成しました。
今回は、私自身が使っている状態管理法freezed + stateNotifier + Provider のProviderの部分をRiverpodに変更して状態管理していこうと思います。

Riverpodとは

Riverpodとは簡単に言うと、Providerの上位互換です。
最近、Flutterの公式ドキュメントにも状態管理の手法としてRiverpodが追加されたみたいです。
Riverpodの公式ホームページは以下です。
Riverpodホームページ

英語ですが、非常にわかりやすいので参考にしてみてください。

何がProviderの上位互換なのかというと、

  • MultiPleProviderのようにWidgetをProviderでラップする必要がなくなった。
  • グローバル変数でProviderを使用可能。
  • BuildContext配下で使う必要がなくなった。
    etc...
    いろいろあります。

雄一の欠点といえば、

  1. これから破壊的な変更がある可能性あり。
  2. 公式ドキュメントがあるが、日本語の説明がほぼない
  3. Hooks的な使い方が出来るのですが、公式がHooksをいまだ認めていない(Hooksなしでも使用可能。)。

riverpodの設定

riverpodを使用する際、3つパターンがあるみたいです。

  1. Flutterのみ使用場合 → flutter_riverpodパッケージ
  2. Dartのみ使用 → riverpodパッケージ
  3. Flutter とflutter_hooksの場合 → flutter_hooks、hooks_riverpodパッケージ

Flutter使用者は、1 or 3を主に使用していきます。
riverpod開発者は3を主に使用しています。

今回は、1の場合、つまりhooksは使わない場合で行っていきます。

Riverpodの使い方

Providerの設定

providerでは上の方でwidgetをラップしていましたが、riverpodの場合はどうやってProviderを設定するのでしょうか、下のコードを見てみましょう。

lib/controller/nwes_controller.dart

//グローバル変数でProviderを設定。
final newsProvider = StateNotifierProvider((ref) => NewsController());

@freezed
abstract class NewsState with _$NewsState {
  factory NewsState({
    bool loading,
    List<Article> articles,
  }) = _NewsState;
}


class NewsController extends StateNotifier<NewsState> {

 
  NewsQueryService _newsQueryService;

  NewsController(this._newsQueryService) : super(NewsState(loading: false));


  Future<void> getNews() async {
    List<Article> articles = [];
    articles = await _newsQueryService.getNews();
    state = state.copyWith(articles: articles);
  }


}

以前は、ProviderをWidgetのなるべく上にラップして置いていましたが、riverpodではその必要がなくなり、
final newsProvider = StateNotifierProvider((ref) => NewsController());
と書くだけでProviderの設定になります。(今回はStateNotifierを使用するため、StateNotifierProvider使用。)

Providerの読み方。

Providerの設定が出来たので、widget内でProviderを読んでみましょう。
以前は、
Provider.of(context, listen :false).getNews();
で、ロジックやstateを読み込んでいました。
Riverpodではどうなのか下のコードを見てみましょう。

lib/controller/nwes_controller.dart

class MainPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          context.read(newsProvider).getNews();
        },
      ),
      appBar: AppBar(
        centerTitle: true,
        title: Text("Demo"),
      ),
      body: HeadPage()
    );
  }
}

class HeadPage extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    //controllerのメソッドを読む場合は、context.read(Provider名).メソッド名と書いて呼び出す。
    final _fetch = context.watch(newsProvider).getNews();
    // TODO: implement build
    return FutureBuilder<void>(
      future: _fetch,
      builder: (context, snapshot) {
        if (snapshot.connectionState != ConnectionState.done) {
          return Center(child: CircularProgressIndicator());
        }
        if (snapshot.hasError) {
          print("エラーが出たよ");
        }
        return HeadNewsListPage();
      },
    );
  }

}

//viewの部分表示
class HeadNewsListPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(top: 10),
      child: Container(
        margin: EdgeInsets.symmetric(horizontal: 10),
        //Hooksを使わない場合はConsumerでProviderを使用する。
        child: Consumer(
          builder:(context, watch, child){
            //stateを呼び出す場合は、watchで監視し(変更を監視)、下のように書くと、NwesState内のstateを取得可能。
            final state = watch(newsProvider.state);
            return ListView.builder(
              itemCount: state.articles.length,
              itemBuilder: (context, index) {
                return ArticleTile(state.articles[index]);
              },
            );
          }
        ),
      ),
    );
  }
}


}

このように、providerを読みだし、widget内で使うことが出来ます。

また、hoksを使用した書き方は、useProviderを使ってよビアスことが出来ます。
ちなみにこのuseProviderはonPressed内では使えないので、上記のcontext.readを使用しましょう。

終わりに

riverpod使ってみた感想は、非常に使いやすいです。
こんご、自分の開発は積極的にriverpodを使用していこうと思うので、hooksを使用した場合などまた記事にできればと思います。

ちなみに、NwesControllerは引数で、NwesQueryServiceもってきているのですが、引数でのもってきかたが下のコードになります。

final newsQueryService = Provider((ref) => NewsQueryService());
final newsProvider = StateNotifierProvider((ref) => NewsController(ref.watch(newsQueryService)));

参考になればと思います!!

10
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?