4

I'm try to set up a profile type page where users can view their information and eventually I'll add features so they can change their data. I'm using Provider to access a Firebase stream <User> which returns the current user's UID (this is working fine). The UID is then used to access their <UserData> stream, but when I try and print UserData().email or any other bits of data it just returns null. The code is as follows:

class Profile extends StatefulWidget {
  @override
  _ProfileState createState() => _ProfileState();
}

class _ProfileState extends State<Profile> {
  @override
  Widget build(BuildContext context) {

    final user = Provider.of<User>(context);

    return StreamProvider<UserData>.value(
      initialData: UserData.initialData(),
      value: DatabaseService(uid: user.uid).userData,
      child: Scaffold(
        appBar: AppBar(),
        drawer: NavigationDrawer(),
        body: ListView(
          children: <Widget>[
            ListTile(
              title: Text(UserData().email),
            )
          ],
        ),
      ),
    );
  }
}

The stream itself looks like this:

  UserData _userDataFromSnapshot(DocumentSnapshot snapshot) {
    return UserData(
      uid: uid,
      email: snapshot.data['email'],
      firstName: snapshot.data['firstName'],
      lastName: snapshot.data['lastName'],
      phone: snapshot.data['phone'],
      dateCreated: snapshot.data['dataCreated'],
      isVerified: snapshot.data['isVerified']
    );
  }

  //User data stream
  Stream<UserData> get userData {
    return userDataCollection.document(uid).snapshots()
        .map(_userDataFromSnapshot);
  }

And the UserData class is just this

class UserData {

  final String uid;
  final String email;
  final String firstName;
  final String lastName;
  final String phone;
  final DateTime dateCreated;
  final bool isVerified;

  UserData({ this.uid, this.email, this.firstName, this.lastName, this.phone, this.dateCreated, this.isVerified });

  factory UserData.initialData() {
    return UserData(
      uid: '',
      email: '',
      firstName: '',
      lastName: '',
      phone: '',
      dateCreated: null,
      isVerified: null,
    );
  }
}

And finally this is the error I'm getting from the ListTile because UserData().email is null, not a string:

A non-null String must be provided to a Text widget.
'package:flutter/src/widgets/text.dart':
Failed assertion: line 285 pos 10: 'data != null'

I thought it may have been an issue with the data not loading in time so when Flutter tries to build the page the data isn't there, but adding the UserData.initialData didn't seem to help. I have managed to get it working using StreamBuilder instead however I don't whether using that is best practice or if I should just do everything with Provider so any help wold be appreciated.

Thanks

1 Answer 1

3

I think you have used the StreamProvider wrong way. In the following code you are creating a new UserData object.

   ListTile(
          title: Text(UserData().email),
        )

Here is aa example how you can use the StreamProvider by creating a separate Widget.

class Profile extends StatefulWidget {
  @override
  _ProfileState createState() => _ProfileState();
}

class _ProfileState extends State<Profile> {
  @override
  Widget build(BuildContext context) {

    return StreamProvider<UserData>.value(
      initialData: UserData.initialData(),
      value: DatabaseService(uid: user.uid).userData,
      child: SecondWidget(),
    );
  }
}

class SecondWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final user = Provider.of<UserData>(context);
    return Scaffold(
      appBar: AppBar(),
      drawer: NavigationDrawer(),
      body: ListView(
        children: <Widget>[
          ListTile(
            title: Text(user.email),
          )
        ],
      ),
    );
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks very much, that works great, though I just kept the final user = Provider.of<User>(context); bit in _ProfileState as that provides the uid needed in the DatabaseService(uid: user.uid)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.