5

I want to get my userid before the build fires in my statefulwidget. If I do this, then build will render before I get my id. If I put it in setstate, my build will use the empty string first and then rerenders it again with my id, but this will cause unnecessary behaviours.

So how do I solve this?

String _userid = '';
Future<Null> setUserid() async {
    SharedPreferences pref = await SharedPreferences.getInstance();

    _userid = pref.getString('FB_USER');

  }
  initState() {
    super.initState();
    setUserid();
  }

Build

// Widget build
new Flexible(
          child: new StreamBuilder<QuerySnapshot>(
            stream: Firestore.instance
                .collection('users')
                .document(_userid)
                .collection('rooms')
                .snapshots(),
            builder:
                (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
              if (!snapshot.hasData) return new Text('Loading...');
              return new ListView(
                children: snapshot.data.documents
                    .map(
                      (DocumentSnapshot document) => new Text('lol'),
                      // )
                      //new OverviewPresentation(presentation: document),
                    )
                    .toList(),
              );
            },
          ),
        ),
Syph
  • 1,239
  • 1
  • 9
  • 16

2 Answers2

7

You can use FutureBuilder

Future<String> setUserid() async {
  SharedPreferences pref = await SharedPreferences.getInstance();

  _userid = pref.getString('FB_USER');
  return _userid;
}

@override
Widget build(BuildContext context) {
  return FutureBuilder(
  future: setUserid(),
  builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
    if (snapshot.hasData) {
      return ... // your widget
    } else return CircularProgressIndicator();
  });

Something like this

Andrii Turkovskyi
  • 27,554
  • 16
  • 95
  • 105
  • don't call the async function within build: https://stackoverflow.com/questions/52249578/how-to-deal-with-unwanted-widget-build – Rémi Rousselet Nov 16 '18 at 10:33
3

You can't, but you can guard against it being null. Also it's easier to move the StreamBuilder to initState

String _userid = '';
dynamic _data;
Future<Null> setUserid() async {
    SharedPreferences pref = await SharedPreferences.getInstance();

    _userid = pref.getString('FB_USER');

    _data = await Firestore.instance
            .collection('users')
            .document(_userid)
            .collection('rooms')
            .snapshots().first;
    setState(() {});
  }
  initState() {
    super.initState();
    setUserid();
  }
  return new Flexible(
      child: 
          if(_data == null) return new Text('Loading...');
          return new ListView(
            children: _data.documents
                .map(
                  (DocumentSnapshot document) => new Text('lol'),
                  // )
                  //new OverviewPresentation(presentation: document),
                )
                .toList(),
          );
        },
      ),
    ),
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Doing it this way means, my widget doesn't listen for data being added or modified in firestore right and if my _userid is empty when I use it, firestore will throw an error since my call will be /'users'//'rooms'/ – Syph Nov 16 '18 at 11:01
  • 1
    You can use `listen()` instead of `first` and move `setState(...)` into `listen(...)` – Günter Zöchbauer Nov 16 '18 at 11:07