skip to Main Content

I am trying to navigate after login inside futurebuilder. api request done successfully but navigation getting error while testing. Help me How to use futurebuilder properly.

child: ElevatedButton(
                onPressed: () {
                  // Validate returns true if the form is valid, or false otherwise.
                  if (_mobileKey.currentState!.validate()) {
                    FutureBuilder<Loginuser>(
                      future: loginuser(mobileController.text.toString(),
                          passwordController.text.toString()),
                      builder: (context, snapshot) {
                        if (snapshot.hasData) {
                          context.go('/Home');
                          return Text(snapshot.data!.message);
                        } else if (snapshot.hasError) {
                          return Text('${snapshot.error}');
                        }

                        // By default, show a loading spinner.
                        return const CircularProgressIndicator();
                      },
                    );
                  }

                  context.go('/Home');
                },
                child: const Text('Submit')),

I tried this its not working. I am using " go_router: ^5.2.4 " for navigation

3

Answers


  1. Chosen as BEST ANSWER

    This method help you to navigate the route without FutureBuilder. see the code

    onPressed: () async {
              // then await the future You want to complete and then use `.then()` 
              //method to implement the code that you want to implement when the future is completed
              await //call your future widget //
                  .then((result) {
                print('future completed');
              // Navigate here 
                // For errors use onError to show or check the errors.
              }).onError((error, stackTrace) {
                print(error);
              });
            }
    

  2. TLDR: Add:

     WidgetsBinding.instance.addPostFrameCallback((_) =>
                    context.go('/Home'));
    
    

    to the FutureBuilder


    I managed to reproduce the problem with this example. Let’s take a look.

    If you run this code:

    import 'package:flutter/material.dart';
    
    void main() => runApp(MainApp());
    
    class MainApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: Scaffold(body: Test()),
        );
      }
    }
    
    class Test extends StatelessWidget {
      const Test({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return FutureBuilder(
            future: printHello(),
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                Navigator.push(
                    context, MaterialPageRoute(builder: (context) => HomePage()));
    
                return Text(snapshot.data.toString());
              } else if (snapshot.hasError) {
                return Text("error");
              } else {
                return Center(child: CircularProgressIndicator());
              }
            });
      }
    }
    
    Future<String> printHello() async {
      return Future.value("Hello");
    }
    
    class HomePage extends StatelessWidget {
      const HomePage({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(body: const Text("home page"));
      }
    }
    

    You’ll see an error:

    setState() or markNeedsBuild() called during build.
    

    So, to fix the problem, you need to use WidgetsBinding.instance.addPostFrameCallback:

    WidgetsBinding.instance.addPostFrameCallback((_) =>
                    Navigator.push(context, MaterialPageRoute(builder: (context) {
                      return HomePage();
                    })));
    
    

    but for your example for go_router, add this line:

     WidgetsBinding.instance.addPostFrameCallback((_) =>
                    context.go('/Home'));
    

    Complete working example:

    import 'package:flutter/material.dart';
    
    void main() => runApp(MainApp());
    
    class MainApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: Scaffold(body: Test()),
        );
      }
    }
    
    class Test extends StatelessWidget {
      const Test({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return FutureBuilder(
            future: printHello(),
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                WidgetsBinding.instance.addPostFrameCallback((_) =>
                    Navigator.push(context, MaterialPageRoute(builder: (context) {
                      return HomePage();
                    })));
    
                return Text(snapshot.data.toString());
              } else if (snapshot.hasError) {
                return Text("error");
              } else {
                return Center(child: CircularProgressIndicator());
              }
            });
      }
    }
    
    Future<String> printHello() async {
      return Future.value("Hello");
    }
    
    class HomePage extends StatelessWidget {
      const HomePage({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(body: const Text("home page"));
      }
    }
    
    

    See also

    setState() or markNeedsBuild called during build

    Login or Signup to reply.
  3. Try removing the FutureBuilder from inside the ElevatedButton instead use Promises i.e then/catch to navigate to new screen

    Updated code:

    child ElevatedButton(
            child: Container(),
            onPressed: () async {
               // Remove the future builder from here
              await loginuser(mobileController.text.toString(),
                      passwordController.text.toString())
                  .then((result) {       
                     context.go('/Home');             // 👈 add your navigatin inside then block 
                  }).onError((error, stackTrace) {
                print(error);
              });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search