Правильно использовать Future Builder внутри стримбордера во Flutter - PullRequest
1 голос
/ 06 августа 2020

Мое требование таково, что всякий раз, когда пользователь проверяет номер телефона, он будет проверять в Firebase, существует ли идентификатор документа, который установлен в качестве номера телефона пользователя, если он ранее вошел в систему, или нет, если существует, тогда Go на домашнюю страницу если этого не происходит, перейдите на страницу подтверждения учетной записи.

Также, если пользователь уже вошел в систему, но не проверил, закрывает приложение, а затем открывает приложение, тогда есть две ситуации: Сначала пользователь подтвердил данные учетной записи или не подтвердил проверяется в процессе проверки. В этом случае я проверю то же самое, существует ли идентификатор документа, для которого установлен номер телефона пользователя, или нет, если существует, а затем go на страницу HomePage else AccountVerification. Это мой код, он не работает идеально. Может ли кто-нибудь предложить мне правильный подход

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  var globalNumber;
  var Number;
  Firestore firestore = Firestore.instance;


  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getCurrentUser();



  }

  @override
  Widget build(BuildContext context) {
    print(globalNumber);
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: StreamBuilder<Object>(
        stream: FirebaseAuth.instance.onAuthStateChanged,
          builder: (BuildContext context, snapshot) {
            if (snapshot.hasData) {
              return FutureBuilder(
                  future: Future.wait([

                    firestore.collection('users').document(globalNumber).get()

                  ]),
                  builder: (BuildContext context,
                      AsyncSnapshot<List> snapshot) {
                    DocumentSnapshot doc = snapshot.data[0];
                    if(snapshot.hasData) {
                      if (doc.exists) {
                        return HomePage();
                      }
                      return AccountDetialsPage();
                    }
                    else{
                      return Container(child: Text('Loading'));
                    }
                  }
              );
            } else {
              return Phoneverification();
            }
          }),
    ) ;
  }

  getCurrentUser() async{

    final FirebaseAuth _auth = FirebaseAuth.instance;
    final FirebaseUser user = await _auth.currentUser();
    final uid = user.uid;
    globalNumber = user.phoneNumber;
    
    // Similarly we can get email as well
    //final uemail = user.email;
    print(uid);

  }

}

1 Ответ

1 голос
/ 06 августа 2020

Он не работает должным образом, как это задокументировано:

«Будущее должно быть получено раньше, например, во время State.initState, State.didUpdateConfig или State.didChangeDependencies. Его нельзя создавать во время вызова State.build или StatelessWidget.buildmethod при создании FutureBuilder. Если future создается одновременно с FutureBuilder, то каждый раз, когда родительский объект FutureBuilder перестраивается, асинхронная задача будет перезапущена ».

Это означает, что когда ваш метод future возвращает значение, происходит перестройка, вызывая еще одну перестройку. Это создает al oop.

Вы должны вызвать вашу будущую функцию на initState(), а затем с этой переменной использовать FutureBuilder внутри метода сборки. Например:

    void main() {
      runApp(MyApp());
    }

    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => _MyAppState();
    }

    class _MyAppState extends State<MyApp> {

      var globalNumber;
      var Number;
      var user;
      Firestore firestore = Firestore.instance;


      @override
      void initState(){
         super.initState();
         getCurrentUser();
      }


      Widget build(BuildContext context){
        return return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: StreamBuilder<Object>(
          stream: FirebaseAuth.instance.onAuthStateChanged,
          builder: (BuildContext context, snapshot) {
            if (snapshot.hasData) {
              return FutureBuilder(
                  future: user,
                  builder: (BuildContext context,
                      AsyncSnapshot<List> snapshot) {
                    DocumentSnapshot doc = snapshot.data[0];
                    if(snapshot.hasData) {
                      if (doc.exists) {
                        return HomePage();
                      }
                      return AccountDetialsPage();
                    }
                    else{
                      return Container(child: Text('Loading'));
                    }
                  }
              );
            } else {
              return Phoneverification();
            }
        }),
      );
    }

    getCurrentUser() async{

      final FirebaseAuth _auth = FirebaseAuth.instance;
      final FirebaseUser user = await _auth.currentUser();
      final uid = user.uid;
      globalNumber = user.phoneNumber;
    
      // Similarly we can get email as well
      //final uemail = user.email;
      print(uid);
    
      getUserNumber(uid);
    }

    //Make another function that you insert into the getCurrentUser(), like this:
    
    getUserNumber(int uid){
      user = Future.wait([
      firestore.collection('users').document(globalNumber).get()
    ]);
  }
...