💬
【Flutter】riverpodのプロバイダ内で、他のプロバイダの状態を更新するサンプルコード
はじめに
下記記事の続編です。
上記記事では、Widget の内側で、「riverpod のプロバイダの状態を更新する方法」について記載しました。本記事では、Widget の外側にあたる、「riverpod のプロバイダ内で、他のプロバイダの状態を更新する方法」について記載します。
解説に利用するアプリの動作イメージ
CountUp ボタンを押下すると、記事一覧に記事が追加され、リスト表示される。
といった動作をするアプリを例に解説します。
コード図解
下記図の ①〜⑧ を順番に見てもらえれば、動作イメージとコードがリンクするかと思います。
そして、本記事で伝えたい要点は ⑤ と ⑦ です。
⑤ は「プロバイダ内で、他のプロバイダの状態を更新する」コードです。
⑦ は「⑤ を発動させるためには、Widget 内で事前に watch しておく必要がある」コードです。
応用
本サンプルの counterProvider の部分(契機になる部分)を置き換えることで、応用できるかと考えています。
サンプルコード全体
サンプルコード全体
lib/main.dart
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'article_page.dart';
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Riverpod Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const ArticlePage(),
);
}
}
lib/article_page.dart
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'article_state_list_provider.dart';
// --------------------------------------------------
//
// counterProvider
//
// --------------------------------------------------
final counterProvider = StateProvider((ref) => 0);
// --------------------------------------------------
//
// ArticlePage
//
// --------------------------------------------------
class ArticlePage extends StatelessWidget {
const ArticlePage({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Article Page"),
),
body: Center(
child: Column(
children: [
ArticlePageParts.countUpButtonWidget(),
ArticlePageParts.articleStateListWidget(),
],
),
),
);
}
}
// --------------------------------------------------
//
// ArticlePageParts
//
// --------------------------------------------------
class ArticlePageParts {
//
// --------------------------------------------------
// countUpButtonWidget
// --------------------------------------------------
static Widget countUpButtonWidget() {
final widet = Consumer(builder: (context, ref, child) {
return ElevatedButton(
onPressed: () {
// counterProviderの値をカウントアップする。
ref.read(counterProvider.notifier).state++;
},
child: Text("Count Up : ${ref.watch(counterProvider)}"),
);
});
return widet;
}
// --------------------------------------------------
// articleStateListWidget
// --------------------------------------------------
static Widget articleStateListWidget() {
final widet = Consumer(builder: (context, ref, child) {
// ArticleStateListの更新をwatch
final articleStateList = ref.watch(articleStateListProvider);
// counterProviderの値がカウントアップされた場合、
// ArticleStateを生成し、ArtcileStateListに追加する処理を実行するためにwatch
ref.watch(addArticleStateListProvder);
return articleStateList.isEmpty
? const Text("No data")
: Expanded(
// ArticleStateListが更新されたらリスト表示する。
child: ListView.builder(
itemCount: articleStateList.length,
itemBuilder: (context, index) {
final articleState = articleStateList[index];
return ListTile(
leading: Text("id : ${articleState.id}"),
title: Text(articleState.title),
);
},
),
);
});
return widet;
}
}
lib/article_state_list_provider.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'article_page.dart';
// --------------------------------------------------
//
// ArticleState
//
// --------------------------------------------------
class ArticleState {
const ArticleState({
required this.id,
required this.title,
});
final int id;
final String title;
}
// --------------------------------------------------
//
// ArticleStateList
//
// --------------------------------------------------
class ArticleStateList extends Notifier<List<ArticleState>> {
List<ArticleState> build() {
return [];
}
void add(ArticleState articleState) {
state = [...state, articleState];
}
}
// --------------------------------------------------
//
// articleStateListProvider
//
// --------------------------------------------------
final articleStateListProvider =
NotifierProvider<ArticleStateList, List<ArticleState>>(() {
return ArticleStateList();
});
// --------------------------------------------------
//
// addArticleStateListProvder
//
// --------------------------------------------------
// counterProvierの値をwatchし、カウントアップされた場合、
// ArticleStateを生成し、AritcleStateListに追加する。
final addArticleStateListProvder = Provider((ref) {
final articleId = ref.watch(counterProvider);
// Provider内で他のProviderの状態を更新するサンプルコード①
unawaited(Future(() {
final articleState =
ArticleState(id: articleId, title: "title : unawaited(Future((){}))");
ref.read(articleStateListProvider.notifier).add(articleState);
}));
// Provider内で他のProviderの状態を更新するサンプルコード②
WidgetsBinding.instance.addPostFrameCallback((_) {
final articleState =
ArticleState(id: articleId, title: "title : addPostFrameCallback");
ref.read(articleStateListProvider.notifier).add(articleState);
});
});
Discussion