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'),
);
}
このように書くことができます.
基本は以上です.また今度応用編も書くかもしれません.