Home > Back-end >  Display data from Firebase in async - Flutter
Display data from Firebase in async - Flutter

Time:01-03

I want to create a profil page where I just display informations from the user, but I have trouble to reach the data. When I want to use my variable user it display 'Instance of Future<Map<String, dynamic>>'

If I put the 'Widget build' in async I have an error message who told me : ProfileScreen.build' ('Future Function(BuildContext)') isn't a valid override of 'StatelessWidget.build' ('Widget Function(BuildContext)').

class ProfileScreen extends StatelessWidget {
  ProfileScreen({super.key});

  @override
  Widget build(BuildContext context) {
    final user = displayUser();
    return Scaffold(
        appBar: AppBar(
          title: Text('Profile'),
        ),
        body: Align(
          alignment: Alignment.topLeft,
          child: Column(
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Align(
                  alignment: Alignment.topLeft,
                  child: Column(children: [
                    Text('Prénom :${user}\nNom :\nEmail :',
                        textWidthBasis: TextWidthBasis.longestLine),
                  ]),
                )
              ]),
        ),
        persistentFooterButtons: [
          SignOutButton(),
          BottomNavBar(),
        ]);
  }

  // Get user informations
  Future<Map<String, dynamic>> displayUser() async {
    final User? currentUser = FirebaseAuth.instance.currentUser;
    late final userUid = currentUser?.uid;
    late final ref = FirebaseDatabase.instance.ref();
    final resSnapshot = await ref.child('/utilisateur/'   userUid!).get();
    final Map<String, dynamic> user = {};

    if (resSnapshot.exists) {
      user['id'] = userUid;
      for (var value in resSnapshot.children) {
        String key = value.key as String;
        var val = value.value;
        user[key] = val;
      }
    } else {
      print('No data available.');
    }
    print(user); // This print display exactly the informations I want.
    return user;
  }
}


Thanks for your help.

CodePudding user response:

Your displayUser is async function and you can't call it inside build method, you need to use FutureBuilder like this:

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Profile'),
      ),
      body: FutureBuilder<Map<String, dynamic>>(
        future: displayUser(),
        builder: (context, snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.waiting:
              return Text('Loading....');
            default:
              if (snapshot.hasError) {
                return Text('Error: ${snapshot.error}');
              } else {
                Map<String, dynamic> user = snapshot.data ?? {};

                return Align(
                  alignment: Alignment.topLeft,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.start,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Align(
                        alignment: Alignment.topLeft,
                        child: Column(
                          children: [
                            Text(
                              'Prénom :${user}\nNom :\nEmail :',
                              textWidthBasis: TextWidthBasis.longestLine,
                            ),
                          ],
                        ),
                      )
                    ],
                  ),
                );
              }
          }
        },
      ),
      persistentFooterButtons: [
        SignOutButton(),
        BottomNavBar(),
      ],
    );
  }

You can customize loading and error state to what you want.

CodePudding user response:

change StatelessWidget to StatefulWidget because userInteract on profileScreen, UserInteraction changes will show on firebase.

class ProfileScreen extends StatefulWidget{ ProfileScreen({super.key});

CodePudding user response:

You can load the user in the initstate and then set user using setstate

class ProfileScreen extends StatefulWidget {
  const ProfileScreen({super.key});

  @override
  State<ProfileScreen> createState() => _ProfileScreenState();
}

class _ProfileScreenState extends State<ProfileScreen> {
  Map<String, dynamic>? user;

  @override
  void initState() {
   final User? currentUser = FirebaseAuth.instance.currentUser;
    late final userUid = currentUser?.uid;
    late final ref = FirebaseDatabase.instance.ref();
    final resSnapshot = await ref.child('/utilisateur/'   userUid!).get();
    Map<String, dynamic> temp = {};

    if (resSnapshot.exists) {
      temp['id'] = userUid;
      for (var value in resSnapshot.children) {
        String key = value.key as String;
        var val = value.value;
        temp[key] = val;
      }
    } else {
      print('No data available.');
    }
    print(temp);
    setState((){
    user =temp 
});
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
          child:
              user != {} ? Text(user.toString()!) : const CircularProgressIndicator()),
    );
  }
}
  • Related