poiuytrez
poiuytrez

Reputation: 22518

Navigator.pop from a FutureBuilder

I have a first screen which ask the user to enter to input, then when the users clicks on a button, the app goes on a second screen which uses a FutureBuilder to call an API.

If the API returns an error, I would like to go back to the previous screen with Navigator.pop. When I try to do that in the builder of the FutureBuilder, I get an error because I modify the tree while I am building it...

setState() or markNeedsBuild() called during build. This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets

What is the proper way to go to the previous screen if an error occur?

class Stackoverflow extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
          child: FutureBuilder<Flight>(
            future: fetchData(context),
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return ScreenBody(snapshot.data);
              } else if (snapshot.hasError) {
                Navigator.pop(context, "an error");
              }
              // By default, show a loading spinner.
              return CircularProgressIndicator();
            },
          )
      ),
    );
  }
}

PS: I tried to use addPostFrameCallback and use the Navigator.pop inside, but for some unknown reason, it is called multiple times

Upvotes: 2

Views: 6566

Answers (2)

user10539074
user10539074

Reputation:

I'd prefer to convert class into StateFullWidget and get rid of FutureBuilder

class Stackoverflow extends StatefulWidget {

  @override
  _StackoverflowState createState() => _StackoverflowState();
}

class _StackoverflowState extends State<Stackoverflow> {
  Flight flight;

  @override
  void initState() {
    super.initState();
    fetchData().then((data) {
      setState(() {
        flight = data;
      });
    }).catchError((e) {
      Navigator.pop(context, "an error");
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: flight != null ? ScreenBody(flight) : CircularProgressIndicator(),
      ),
    );
  }
}

and of cause pass context somewhere outside class is not good approach

Upvotes: 2

Viren V Varasadiya
Viren V Varasadiya

Reputation: 27137

You can not directly navigate when build method is running, so it better to show some error screen and give use chance to go back to last screen.

However if you want to do so then you can use following statement to do so.

Future.microtask(() => Navigator.pop(context));

Upvotes: 8

Related Questions