【Flutter ✖️ Riverpod】buildメソッド内で画面遷移する方法

2023/02/11に公開

buildメソッド内で、画面遷移したい・・・
と思って下記のコードを書いた事があるはずです

buildメソッド
@override
Widget build(BuildContext context, WidgetRef ref) {
 Navigator.push(MaterialPageRoute...);
}

でも、これってエラーになるんですよね。

Error: The following assertion was thrown while dispatching notifications for GoRouterDelegate:
setState() or markNeedsBuild() called during build.

UIを構築中に画面遷移するなって事なんでしょうね。

まぁ、ここで画面遷移とかダイアログ出したい
気持ちは痛いほど分かります。

もし、するならinitState上でFuture処理をすると良いよって記事があったので
よかったら参考にしてみてね。
なんかinitState上でFuture処理すると最後に処理が回るらしい。

なるほど、だからエラーにならんわけだ。

  @override
  void initState() {
    super.initState();
    Future(() {
      Navigator.push(context, MaterialPageRoute(builder: (context) {
        return ThirdPage();
      }));
    });
  }

参考:
https://nobushiueshi.com/flutterinitstateで画面遷移する方法/

本命はRiverpod

ということで、今回はriverpodを使ってどうやるのか
という事ですが・・・

下記のコードでなんとなく理解して下さいmm

final userInfoFutureProvider = FutureProvider<bool>((ref) async {
  print('userInfoFutureProviderスタート');
  await Future.delayed(const Duration(seconds: 2));
  return true;
});
buildメソッド
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    ref.listen(userInfoFutureProvider, (previous, next) async {
      print('listen発火');
      context.go('/login');
      print('画面遷移済み');
    });

    return const Scaffold();
  }

うん、例が最悪な気がする。ということで、公式の方を見て下さいねmm

https://riverpod.dev/ja/docs/concepts/reading#reflisten-を使ってプロバイダを監視する

どうやら、ref.listenを使用すると、buildメソッド内でも、
問題なくcontext.goとかnavigatorとかダイアログをぶち込むことが出来るらしい。知らんけど。
理由はよく分からん。

普通はElevatedButtonとかで呼び出すんかなぁとか思ってたけど、逆に
ElevatedButtonとかでは呼び出すなって書いてるから不思議よねぇ。
まぁ、そっちは基本的にref.read使うから別に不思議でもないかぁ。

ということで、ref.listenを使用すると画面遷移できるらしいから、ぜひ使ってみてちょ。

Discussion