DB Cooper
DB Cooper

Reputation: 93

Flutter Firestore check if user exists via StreamBuilder:

I'm trying to add a check in my app via a StreamBuilder to show users different screens based upon if a user's document exists in Firestore. My code technically works but on hot reload, it shows my 'AddUser' screen for a couple of seconds before moving over to my 'UserHomeScreen'. I was wondering how to rectify this so the 'AddUser' screen does not show my 'AddUser' screen at all if the user document exists.

Here is my code:

class UserStream extends StatelessWidget {
  const UserStream({Key? key}) : super(key: key);
  

  @override
  Widget build(BuildContext context) {
    FirebaseAuth auth = FirebaseAuth.instance;
     String uid = auth.currentUser!.uid.toString();
    return StreamBuilder<dynamic>(
      stream: FirebaseFirestore.instance.collection('users').doc(uid).snapshots(),
      builder: (context, snapshot) {
        if (snapshot.hasData && snapshot.data!.exists) {
          return const UserHomeScreen();
        } else {
          return AddUser(youtubeLink: '', bio: '', bioLink: '', displayName: '', instaLink: '', profilePhoto: '', tiktokLink: '', username: '',);
        }
      },
    );
  }
}

Upvotes: 0

Views: 635

Answers (2)

BIS Tech
BIS Tech

Reputation: 19434

I think your solution is not a good practice. This is my solution.

You have to create some splash/landing screen to handle your logic.

    class LandingPage extends StatefulWidget {
      @override
      _LandingPageState createState() => _LandingPageState();
    }
    
    class _LandingPageState extends State<LandingPage> {
     final FirebaseAuth auth = FirebaseAuth.instance;
     final FirebaseFirestore db = FirebaseFirestore.instance; 
    
      @override
      void initState() {
        super.initState();
        String? uid = auth?.currentUser?.uid;
        if(uid == null) {
          Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => AddUser(youtubeLink: '', bio: '', bioLink: '', displayName: '', instaLink: '', profilePhoto: '', tiktokLink: '', username: '',)));     
        } else {
          db.collection('users').doc(uid!).get().then((doc) {
          var user = doc.data();
    
          if(user != null) {
            Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => UserHomeScreen()));
          } else {
            Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => AddUser(youtubeLink: '', bio: '', bioLink: '', displayName: '', instaLink: '', profilePhoto: '', tiktokLink: '', username: '',)));       
          }
       }
   });
 }
}

 @override
  Widget build(BuildContext context) {
    return Scaffold(); // some loading UI
  }

Upvotes: 1

Stefan Galler
Stefan Galler

Reputation: 831

You could structure your builder like this:

builder: (context, snapshot) {
  if (snapshot.hasData) {
    if (snapshot.data!.exists){
      return const UserHomeScreen();
    } else {
      return AddUser(youtubeLink: '', bio: '', bioLink: '', displayName: '', instaLink: '', profilePhoto: '', tiktokLink: '', username: '',);
    }
  } else {
    return CircularProgressIndicator();
  }
},

This way, you show a CircularProgressIndicator while the snapshot is resolving. At this point, you don't know of your data exists or not.

As soon as the snapshot is resolved and you have information, whether your data exists, you can show the respective screen.

Upvotes: 2

Related Questions