Reputation: 81
I have this code which fetch data from Firestore
and I have setState
during build, but it keeps giving warnings about memory leak, however it's updated, but I need a way that avoid this warning, here is simple sample
bool isOne = false ;
//Stfl Widget
Widget build(BuildContext context) {
return Stack( //edit
children [
!isOne? Text('bool varible is false')
: Text('bool varible is true')
FutureBuilder(
future: FirebaseFirestore.instance.collection('users')
.doc('userId').get(),
builder: (context, AsyncSnapshot snapshot) {
if(!snapshot.hasData){
return Text('');
}else{
if(mounted) {
setState(() {
isOne = true ; // memory leak warning
});
}
}
return snapshot.data['name'];
also I tested this but the same warning
WidgetsBinding.instance!.addPostFrameCallback((_) => setState(() {}));
How can I handle that type of simple update during build tree without any memory leak causing?
Upvotes: 1
Views: 712
Reputation: 864
You have no need to set state. The FutureBuilder
already rebuilds it's build
method when the future finishes. You can just put this FutureBuilder
around anything you want to update and use the snapshot.data
to process.
Just as a bonus tip: FutureBuilders
have a initialData
parameter so you can use that and be sure that you never receive null
values for example!
Edit:
Here is an example of how to do something like what you want to achieve using Bloc's Cubit base class. You could do something like this and create this cubit variable up in your widget tree and then pass it down wherever you want. Wherever you use this NewWidget
and pass the same variable instance they will all update together.
final cubit = DocGetter(
() {
return FirebaseFirestore.instance.collection('users').doc('userId').get()
},
);
cubit.futureUpdate(
FirebaseFirestore.instance.collection('users').doc('userId').get(),
);
cubit.futureUpdateFunction(
FirebaseFirestore.instance.collection('users').doc('userId').get,
);
class NewWidget extends StatelessWidget {
const NewWidget({
Key? key,
required this.child,
required this.getter,
this.childWhileEmpty,
}) : super(key: key);
final Widget child;
final Widget? childWhileEmpty;
final DocGetter getter;
@override
Widget build(BuildContext context) {
return StreamBuilder<Map>(
initialData: cubit.state,
stream: cubit.stream,
builder: (context, snapshot) {
final map = snapshot.data!;
if (map.isEmpty) {
return childWhileEmpty ?? const SizedBox.shrink();
} else {
return child;
}
},
);
}
}
class DocGetter extends Cubit<Map> {
DocGetter(Future<Map> Function() fn, {Map? initialState})
: super(initialState ?? {}) {
fn().then(update);
}
Future<void> futureUpdateFunction(Future<Map> Function() fn) async {
final map = await fn();
emit(map);
}
Future<void> futureUpdate(Future<Map> futureMap) async {
final map = await futureMap;
emit(map);
}
void update(Map newMap) => emit(newMap);
}
Upvotes: 1