WidgetやProviderのライフサイクルについて調べてみた
現在Flutterでアプリ開発をしているのですが、ウィジェットやProviderのライフサイクル周りで少しハマりました。
そこで今回の記事ではWidgetやProviderのライフサイクルについて紹介したいと思います。
ハマったケース1
問題
CustomScrollView
内にProvider
を複数配置した時にBlocA、BlocBは生成されますが、BlocCは生成されない
解決方法
この問題の原因はウィジェットのライフサイクルにあります。 スクロール可能な画面において、ウィジェットは画面外に出てしまうと自動で破棄され、再び画面内に入るときに生成されるようです。
今回のケースではBlocA、BlocBを注入するProvider<BlocA>
・Provider<BlocB>
はすでに画面内に存在するため生成済みとなりますが、BlocCを注入するProvider<BlocC>
は画面外のため未生成となります。
これより、画面の生成時にBlocA・locB・BlocCを注入するProvider
をすべて生成するにはCustomScrollView
の位置でMultiProvider
をつかうなどして各Provider
を生成すれば良さそうです。
ただし、この方法でProvider
を生成してしまうとCustomScrollView
以下全てのウィジェットから全てのBlocにアクセスできてしまうので注意が必要です。
私はBlocの肥大化を防ぐためにBlocを分割したかったので、今回のケースではどこからでもBlocへアクセスできることには目を瞑ることにしました。
ハマったケース2
問題
先ほどのケース1を踏まえウィジェットの構成を修正してみました。
CustomScrollViewr
より親でMultiProvider
を使ってBlocを注入するよう変更しました。
しかし、ここでまた問題が発生しました。
Provider
は全て生成済みですが、BlocCは未生成のままです。
解決方法
今回のケースの問題はProvider.of<Bloc>(context)
のタイミングにあります。
Provider
がcreate
を呼ぶタイミングはProvider.of()
が初めて呼ばれるタイミングであって、Provider
を生成するタイミングではないようです。
今回のケースではBlocA
・BlocB
をProvider.of()
するウィジェットは画面内に存在していますが、BlocC
をProvider.of()
するウィジェットは画面外にあります。
問題1よりウィジェットは画面内に入ってきて初めて生成されるようなので、BlocC
をProvider.of()
するウィジェットは生成されておらず、そのためProvider.of<BlocC>(context)
が呼ばれていないためBlocC
が未生成となるようです。
この問題を解決する安直な方法として予めCustomScrollView
の外でProvider.of<BlocC>(context)
をしておくことが考えられます。
ですが、Blocを必要としない場所でProvider.of()
をすることはあまり良くないように思えます。
幸いProviderにはこの問題を解決してくれるlazy
というパラメータが用意してありました。
lazy
は注入したいインスタンスを遅延初期化するかどうかについてのパラメータで、何も指定しなければ遅延初期化するようです。
laze
にはbool
を渡すことができ、laze = false
とすることで遅延初期化を無効化できます。
これにより全てのBlocを全て生成することができました。
おわりに
今回はウィジェットとProviderのライフサイクルについてまとめました。
今回のハマりを通し、ライフサイクルの理解度がフレームワークを使いこなす鍵になると改めて感じました