Home > front end >  How to refresh StatefulWidget after called Navigator.pushNamed()
How to refresh StatefulWidget after called Navigator.pushNamed()

Time:10-26

What I'm doing

There are two pages: profile and login page.

The profile page is shown first, but when user not already logged in, profile page doesn't show profile and show login button.

Profile code

bool loggedin = false;      // If user already logged in return true


class Profile extends StatefulWidget {
  const Profile({Key? key}) : super(key: key);

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

class _Profile extends State<Profile> {

  @override
  Widget build(BuildContext context) {
    return loggedin
        ? Column(children: [  //.... some user information
                     ])
        : needLogin(context);
  }
}

Widget needLogin(BuildContext context) {
  return Center(
            TextButton(
            onPressed: () {
              Navigator.of(context).pushNamed("/login");
            },
            child: const Text(
              "Login",
              style: TextStyle(fontSize: 20),
            )),
      );
}

Loggin page

// The code to login is omitted. if login succeeded do loggedin = true; in setState()

var user = FirebaseAuth.instance.currentUser;
if (user != null) {
  Navigator.of(context).pop();
  setState(() {
    loggedin = true;
  });
}

// Then back to profile page automatically 

Problem

I did loggedin = true; in setState() but profile page still shows login button of needLogin().

The reason I wrote needLogin() outside of StatefulWidget is to reuse it with other StatefulWidget.

Question

How can I update previous page when call setState() in the page which generated by Navigator.of(context).pushNamed().

CodePudding user response:

Don't

loggedin

outside of the widget.

Use it within:

class _Profile extends State {

Also, you may want to look into some State Management techniques like Provider with Change Notifier for instance. It's quite easy to use and will do exactly what you need.

UI shouldn't contain the business logic and should be rendered based on some sort of controller. This makes code more consistent, readable and testable.

CodePudding user response:

You have to edit the needLogin method and also pass the success state/bool back through the Navigator:

Profile Code

 class Profile extends StatefulWidget {
  const Profile({Key? key}) : super(key: key);

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

class _Profile extends State<Profile> {

  @override
  Widget build(BuildContext context) {
    return loggedin
        ? Column(children: [  //.... some user information
                     ])
        : needLogin(context, () => setState(() {loggedIn = true}));
  }
}


 Widget needLogin(BuildContext context, void Function() setStateFunction) {
    return Center(
      child: TextButton(
          onPressed: () async {
            await Navigator.of(context)
                .pushNamed("/login")
                .then((result) {
              if (result as bool) {
                setStateFunction.call();
              }
            });
          },
          child: const Text(
            "Login",
            style: TextStyle(fontSize: 20),
          )),
    );
  }

Login page


var user = FirebaseAuth.instance.currentUser;
if (user != null) {
   Navigator.pop(context, true);
}
  • Related