Flutterで開発をしている皆さんこんにちは,今回はRiverpodの使い方を紹介してきます.
私はちょっと特殊な経歴で,React.jsを4ヶ月くらい勉強してから,Flutterに鞍替えした人間です.
そんな僕からすると「なんでRiverpod使わないの?」って思うくらい使いやすいです.
まず皆さんに言いたいのが,FlutterはどんどんReactに近づいているということ.
特にDartパッケージのProviderが登場したあたりから,Reactに近づいている印象です.
state managementが非常にReactに似ていると思います.
さらにFlutter hooksというパッケージが出てきたので,さらにReactに近づくことになりました.
というよりFlutter hooksの最初の説明にReactのhooksの真似ですと書かれています.
今回はflutter_hooksとhooks_riverpodを使ったstate manegementのやり方を解説します.
ステップ1:インストール
今回はflutter_hooksという別のパッケージを使って,hooks_riverpodという状態管理用のパッケージを動かすイメージです.
つまり2つのパッケージをインストールしなければいけません.
以下のようにpubspec.yamlを編集します.
これは,この記事を書いた当時のバージョンなので実際のバージョンを知るために こちら
dependencies:
flutter:
sdk: flutter
flutter_hooks: ^0.17.0
hooks_riverpod: ^0.14.0+4
ステップ2:下準備
Riverpodを使うためには,main.dartを少し改良しなければいけません.
具体的には以下の通りです.
void main() {
runApp(
ProviderScope(
child: MyApp(),
),
);
}
上のようにrunApp()の中にProviderScopeを追加します.
ステップ3:stateを定義する
やっとstateを定義するところまで来ました.
stateを定義すれば,それ以降stateを定義したファイルをimportすれば,どこでもstateを読み取り,書き取りすることができます.
実際に定義の仕方をお見せしましょう.
final helloWorldProvider = Provider((_) => 'Hello world');
今回はProviderの名前がhelloWorldProviderになります.値を呼び出すときはこの名前を使用します.
またProviderの初期値,つまり初期のstateがHello worldとなります.他の状態管理と同様にこの値は後から変更することができます.
ここで注目してほしいのが,providers.dartというファイルで定義されているということ.
私のおすすめはmain.dartなどで使う場合でも,このコードはstate定義用の専用ファイルを作成しておくのがおすすめです.
stateが何個あろうと,state定義用ファイルを一つだけimportするだけで,全てのstateの読み書きができるので便利です.
実はProvider以外にもstateを定義する方法があるのですが,今回は私がよく使うものを一つだけ教えます.
それはStateProvderです.
final helloWorldProvider = StateProvider((_) => 'Hello world');
このようにProviderと同じように使えますが,StateProviderの方が値を読み取ることに優れています.
値の読み取り方については別の章で教えます.
ステップ4:値を読み取る・変更する
まずは値の読み取り方を学びましょう.
実はRiverpodでは値を変更するのは,値を読み取ることの応用となっています.
早速,具体例から学んでいきましょう.
値を読み取る
final counterProvider = StateProvider((ref) => 0);
class Count extends HookWidget {
@override
Widget build(BuildContext context) {
int count = useProvider(counterProvider).state;
return Text('$count');
}
}
ここで重要なのは,通常classを作成する場合はStatelessWidgetを使用しますが,今回はflutter_hooksというパッケージを導入しているため,HookWidgetという特殊なWidgetを継承できます.
ここでHookWidgetに関して説明すると,HookWidgetはStatelessWidgetを内包しているので,StatelessWidgetでできることは全てできます.
HookWidgetではそれプラスhooksというものが使えます.
そのhooksの一つが,useProviderです.上のようにしてcountにProviderの中に入っている値を代入することができます.
この値はProviderの中の値が変更された時も,しっかりと反映されますのでご安心ください.
ここで注意しなければならないのが,useProvider(counterProvider).stateというコードです.
.stateという書き方ができるのは,StateProviderで定義した場合のみです.
普通のProviderで定義した場合は,.stateと書いてもエラーが出るだけです.
ちょっと一息
最近のコーディングでは,めんどくさいのでStatelessWidgetを一回も継承していません.
理由はhooksを使うかどうかは,classを作成している段階ではわからない時もあります.しかしhooksを使おうと使うまいとHookWidgetを継承しておけば事足りるので,StatelessWidgetを使う必要はないのです.
むしろclassを作成するたびに,hooksを使うかどうかを考えて,StatelessWidgetとHookWidgetのどちらを使うか考えていたら,あっという間に時間は過ぎていきます.
値を変更する
ここからは少し応用編になります.
Riverpodでは値の読み取り方は様々です.
先ほどはその中で最も簡単な方法をご紹介しました.
値を変更する場合はもう一つの値の読み取り方を応用します.
具体例を見ていきましょう.
カウンターの場合
final counterProvider = StateProvider((ref) => 0);
@override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: () => context.read(counterProvider).state++,
child: Text('increment'),
);
}
文字列の場合
final textProvider = StateProvider((ref) => 0);
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
context.read(textProvider).state = 'Hello hello everybody^_^';
},
child: Text('increment'),
);
}
このように書くことができます.
基本は以上です.また今度応用編も書くかもしれません.