はじめに
こんにちは、とりかつ(@torikatsu923)です。
私はStateNotifier+Riverpod+Freezedを使用してMVVMライクにFlutterアプリを開発しています。 4月の頭にriverpodが0.13.1+1から0.14.0にアップデートされたのですが、このアップデートでは破壊的変更が入っていました。
この破壊的変更に気づかず、いつものようにRiverpodのproviderからStateNotifierを取得しようとしたところ、うまく取得できずに沼にハマりました。
この記事を執筆したのは4/19日ですが、どうやら公式docはこの破壊的変更に対応していないようです。 なので、今回はバージョンアップに伴う仕様変更の一部について解説をしたいと思います。
手っ取り早く確認したい方はpub devのchangelogを参照してください。
はまったこと
ここではカウンターアプリを例として取り上げます。
初めに以下のようなCounterController
というコントローラがあるとします。
このコントローラはカウンターのカウント数の状態と、カウントを一個増やすincrement
というメソッドを持っています。
counter_controller.dart
class CounterController extends StateNotifier<int> { Counter(): super(0); /// カウントを一個増やす void increment() => state++; } final counterProvider = StateNotifierProvider((ref) => Counter());
UI側でボタンのコールバックにCounterController
のincrement
を紐付けようと以下のコードを書きました。
app.dart
class App extends StatelessWidget { @override Widget build(BuildContext context, ScopedReader watch) { final CounterController counter = context.read(counterProvider); return RaisedButton( onPressed: counter.increment, child: Text('increment'), ); } }
一見問題なさそうなコードに見えます。 いままでならこれで問題なく動いたのですが、v0.14.0の破壊的変更によってこの方法は使えなくなりました。
まず、context.read
の戻り値がdynamic
になってしまうのでapp.dart
の以下の行がコンパイルエラーになってしまいます。
final CounterController counter = context.read(counterProvider);// return dynamic
これを解決するためにStateNotifierProvider
に型パラメータを設定する必要があります。
1個目の型パラメータにはStateNotifier
の型を、2個目の型パラメータにはStateNotifier
が保持する型を持たせる必要があります。
修正後のCounterController
は以下のようになります。
counter_controller.dart
class CounterController extends StateNotifier<int> { Counter(): super(0); /// カウントを一個増やす void increment() => state++; } /// 型パラメータの追加 final counterProvider = StateNotifierProvider<CounterController, int>((ref) => Counter());
型パラメータを追加することでcontext.read
の戻り値がdynamic
ではなくなりました。
しかし、まだコンパイルエラーは消えません。
app.dartの以下のコードではCounterControllerを取得したいのですが、context.read
の戻り値はint
になってしまいます。
final CounterController counter = context.read(counterProvider);// return int type
これではincrement
へアクセスすることができません。
これも破壊的変更の影響です。
state
ではなくCounterController
(StateNotifier
)へアクセスしたい場合はnotifier
を追加する必要があります。
以下は修正後のコードになります。
final CounterController counter = context.read(counterProvider.notifier);// return CounterController type
counterProvider
のすぐ後ろにnotifier
がついていることがわかると思います。
これで、無事にボタンとCounterController.increment
を紐づけることができました!
おわりに
今回はriverpodの破壊的変更について紹介しました。 もし間違っている部分があればご連絡いただければ幸いです。
flutterはとても便利なフレームワークですが、新しい分枯れたライブラリが少ないです。 そのため日々、変更を追っていかないと一瞬で置いてけぼりにされてしまうので、注意をしなければと改めて思いました。
それでは、よい開発ライフを!