Home > Back-end >  User state managment with firebase and provider
User state managment with firebase and provider

Time:08-04

My goal is to provide all the data of the logged in user throughout the app using provider and use it to customize the UI based on the user.

The problem is that the data takes time to arrive from Firestore and at the start of the application the provider is not able to provide the widgets of the home screen, so I get the next error:

Exception has occurred. _CastError (Null check operator used on a null value)

When I click "continue" in debug options then the interface get the data from the user correctly and all works fine, so I understand that I need a way to wait the data to be available.

I know that the returns of type Future have methods to deal with the asynchronous response from Firestore, but in order to use provider I have "synchronized" that data using try{}catch(e){} as shown in the code.

class CurrentUserProvider extends ChangeNotifier {
  UserModel _currentUser = UserModel();

  UserModel get getCurrentUser => _currentUser;

  void updateStateFromFirebase(String uid) async {
    try {
      _currentUser = await OurDatabase().getUserInfo(uid);
      notifyListeners();
    } catch (e) {
      print(e);
    }
  }
}

getUserInfo(uid){} is the async function that download the current user data from firestore using the uid provided by Authentification Firebase after the user logged in.

To my knowledge this implies that _currentUser is not going to be async anymore, so I cannot create an alternative to represent something on the screen while the data is arriving.

This is the code where I receive the data from the provider and try to render _currentUser.uid as text on the screen.

import 'package:beeteam/providers/currentUserProvider.dart';
import 'package:flutter/material.dart';
import 'package:beeteam/models/user_model.dart';
import 'package:provider/provider.dart';

class MyTeams extends StatefulWidget {
  @override
  State<MyTeams> createState() => _MyTeamsState();
}

class _MyTeamsState extends State<MyTeams> {
  @override
  Widget build(BuildContext context) {
    UserModel? _currentUser =
        Provider.of<CurrentUserProvider>(context, listen: true).getCurrentUser;
    return Scaffold(
        body: Container(
          margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 20),
          child: Text(_currentUser.uid!),
          //Text(_currentUser.uid!),
        ),
        floatingActionButton: FloatingActionButton(
            child: Icon(Icons.add),
            backgroundColor: Color.fromARGB(255, 190, 158, 62),
            onPressed: () {
              Navigator.of(context).pushNamed('/join_team_screen');
            }));
  }

I got an error if I dont code ! at the end of _currentUser.uid.

This is the UserModel code.

class UserModel {
  String? uid;
  String? email;
  String? firstName;
  String? secondName;
  String? userName;
  String? teamSelected;
  List<String>? teamsMemberUid;
  List<String>? notifications;

  UserModel(
      {this.uid,
      this.email,
      this.firstName,
      this.secondName,
      this.userName,
      this.teamSelected,
      this.teamsMemberUid,
      this.notifications});

Do you have any idea how to solve this problem?

CodePudding user response:

Make currentUser nullable allowing null value before loading is finished.

class CurrentUserProvider extends ChangeNotifier {
  UserModel? _currentUser;

  UserModel? get currentUser => _currentUser;

  void updateStateFromFirebase(String uid) async {
    try {
      _currentUser = await OurDatabase().getUserInfo(uid);
      notifyListeners();
    } catch (e) {
      print(e);
    }
  }
}

Show loading state while currentUser is null.

class MyTeams extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    UserModel? currentUser =
        Provider.of<CurrentUserProvider>(context, listen: true).currentUser;
    return Scaffold(
        body: currentUser == null
            ? const Center(child: CircularProgressIndicator())
            : Container(
                margin:
                    const EdgeInsets.symmetric(horizontal: 10.0, vertical: 20),
                child: Text(currentUser.uid!),
              ),
...
  }
}
  • Related