Flutter - trigger navigation when Provider variable changes

4,617

Solution 1

Instead of trying to navigate to a new view what you should do is display the loading splash screen if you are still waiting for data and once that changes display your main home view, like this:

import 'package:catalogo/firebase/ProductData.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class Main extends StatefulWidget {
  @override
  _MainState createState() => _MainState();
}

class _MainState extends State<Main> {
  bool shouldProceed = Provider.of<ProductData>(context, listen: true).shouldProceed;

  @override
  Widget build(BuildContext context) {
    if(shouldProceed){
      return Home();
    }else{
      return RouteSplash();
    }
  }
}

Solution 2

Use BlocListener as in this example:

BlocListener(
    bloc: BlocProvider.of<DataBloc>(context),
    listener: (BuildContext context, DataState state) {
        if (state is Success) {              
            Navigator.of(context).pushNamed('/details');
        }              
    },
    child: BlocBuilder(
        bloc: BlocProvider.of<DataBloc>(context),
        builder: (BuildContext context, DataState state) {        
            if (state is Initial) {
                return Text('Press the Button');
            }
            if (state is Loading) {
                return CircularProgressIndicator();
            }  
            if (state is Success) {
                return Text('Success');
            }  
            if (state is Failure) {
                return Text('Failure');
            }
        },
    }
)

Source: https://github.com/felangel/bloc/issues/201

Share:
4,617
William Terrill
Author by

William Terrill

Updated on December 16, 2022

Comments

  • William Terrill
    William Terrill over 1 year

    I'm trying to show a splash screen on initial app startup until I have all of the data properly retrieved. The retrieval is done by a class called "ProductData" As soon as it's ready, I want to navigate from the splash page to the main screen of the app.

    Unfortunately, I can't find a good way to trigger a method that runs that kind of Navigation and listens to a Provider.

    This is the code that I'm using to test this idea. Specifically, I want to run the command Navigator.pushNamed(context, 'home'); when the variable shouldProceed becomes true. Unfortunately, the code below gives me the error, "setState() or markNeedsBuild() called during build."

    import 'package:catalogo/firebase/ProductData.dart';
    import 'package:flutter/material.dart';=
    import 'package:provider/provider.dart';
    
    class RouteSplash extends StatefulWidget {
      @override
      _RouteSplashState createState() => _RouteSplashState();
    }
    
    class _RouteSplashState extends State<RouteSplash> {
      bool shouldProceed = false;
    
      @override
      Widget build(BuildContext context) {
        shouldProceed =
            Provider.of<ProductData>(context, listen: true).shouldProceed; 
        if (shouldProceed) {
          Navigator.pushNamed(context, 'home'); <-- The error occurs when this line is hit.
        } else {
          return Scaffold(
            body: Center(
              child: CircularProgressIndicator(),
            ),
          );
        }
      }
    }
    

    Is there a better way to navigate to a page based on listening to the results of a provider?