Flutter каков наилучший подход для совместного использования navigator и ChangeNotifierProvider

#flutter #flutter-provider #flutter-navigation #flutter-change-notifier

#flutter #flutter-provider #flutter-навигация #flutter-change-notifier

Вопрос:

Я новичок в flutter, этот вопрос может быть очень простым. Для реализации этого у меня есть страница авторизации firebase phone, если пользователь вошел в систему, затем перейдите на домашнюю страницу, если пользователь является новым пользователем, затем перейдите на страницу регистрации

Проблема в том, что всякий раз, когда значения изменяются у поставщика, потребитель получает уведомление и перестраивает метод сборки. Я не смогу прослушать их в методе сборки и вернуть Navigator.of(context).pushNamed() . Есть идеи, как правильно использовать ChangeNotifierProvider вместе со слушателями и соответствующей навигацией по страницам?

У меня есть класс входа и класс поставщика, как показано ниже,

 class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
        @override
          Widget build(BuildContext context) {
            return ChangeNotifierProvider(
              create: (_) => LoginProvider(),
              child: Consumer<LoginProvider>(builder: (context, loginState, child) {
                return Scaffold(
                  ...
                  body: RaisedButton(
                  onPressed: **loginState.doLogin(_textController.text, context);**
                   ...
                )
              }),
           );
         }
   }

class LoginProvider with ChangeNotifier {
     bool _navigateToSignup = false;
     bool get navigateToSignup => _navigateToSignup;

    Future doLogin(String mobile, BuildContext context) async {
        FirebaseAuth _auth = FirebaseAuth.instance;
        _auth.verifyPhoneNumber(
          ...
          verificationCompleted: (AuthCredential credential) async {
          UserCredential result = await _auth.signInWithCredential(credential);
          User user = result.user;
          // if user is new user navigate to signup
          // do not want to use Navigator.of(context).pushNamed('/signupPage'); here, instead would like to notify listeners at login page view and then use navigator.
          if (user.metadata.creationTime == user.metadata.lastSignInTime) {
            _navigateToSignup = true;
          } else {
            if (result.user != null) {
              _navigateToHome = true;
              //Navigator.of(context).pushNamedAndRemoveUntil('/homePage', ModalRoute.withName('/'));
            } 
          }
          notifyListeners();
        },
          ...
         );
    }
}
  

Заранее спасибо.

Ответ №1:

Существует несколько подходов, вы выбираете тот, который подходит вам лучше всего.

  1. Передайте context ChangeNotifier , как вы уже делаете. Мне это тоже не нравится, но некоторые люди это делают.

  2. Передайте обратный вызов вашему ChangeNotifier , который будет вызван, когда вам нужно перейти. Этот обратный вызов будет выполнен вашим кодом пользовательского интерфейса.

  3. То же, что и 2, но вместо обратного вызова экспортируйте a Stream и выдайте событие, указывающее, что вам нужно перейти. Затем вы просто слушаете это Stream в своем пользовательском интерфейсе и переходите оттуда.

  4. Используйте a GlobalKey для своего навигатора и передайте его своему MaterialApp , чем вы можете использовать этот ключ везде. Подробнее здесь.

Комментарии:

1. Спасибо, я подумал о 3-м пункте и попробовал ниже .. это работает.. Страница входа в систему имеет ниже void _navigationController() { _loginProvider.gotoHomePage.stream.listen((событие) { Navigator.of(context).pushNamed(‘/homePage’) } и у провайдера будет StreamController<bool> _gotoHomePage = StreamController<bool>(); StreamController<bool> получить gotoHomePage => _gotoHomePage;

2. Обычно я выбираю вариант 2, поскольку мне не нужно иметь дело со сложностями потоков, такими как не забыть отменить подписку и немного более сложный код… Но все варианты имеют свое место.