Reputation: 329
I have a method like this in my provider file to update a list of items from server :
Future<void> getServerMeals(String userName, String date) async {
final QueryBuilder<ParseObject> parseQuery =
QueryBuilder<ParseObject>(ParseObject('UsersEaten'));
parseQuery
..whereContains('eatenBy', userName)
..whereEqualTo('eatenDate', date);
final ParseResponse apiResponse = await parseQuery.query();
if (apiResponse.success && apiResponse.results != null) {
List<dynamic>? apiRes = apiResponse.results;
List<dynamic> newMeals = apiRes!
.map((e) => EatenItem(
id: e['objectId'],
eatenCal: e['eatenCal'],
eatenTitle: e['eatenTitle'],
eatenImageUrl: e['eatenImg'],
userId: e['objectId'],
))
.toList();
_eatenMeals = newMeals;
print(apiResponse.results);
}
}
and in my main screen I've wrapped that list into the FutureBuilder it works fine and return a list:
Container(
height: MediaQuery.of(context).size.height * 0.6,
margin: EdgeInsets.only(left: 30, right: 30),
child: FutureBuilder(
builder: (ctx, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
return ListView.builder(
itemCount: mealsList.eatenMeals.length,
itemBuilder: (ctx, index) =>
DailyEaten(mealsList.eatenMeals[index]),
);
},
future: Provider.of<EatenMeals>(context)
.getServerMeals(currentUser.username, now),
),
),
but when I've added notifylistener() in my method my future builder list stuck on waiting state and won't update list what's wrong here
Upvotes: 1
Views: 1388
Reputation: 329
@nvoigt
here is my widget and I've removed those Providers from build method
class TimelineWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
child: FutureBuilder(
future: Provider.of<EatenMeals>(context, listen: false).getServerMeals(),
builder: (ctx, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
return Consumer<EatenMeals>(
builder: (ctx, mealsList, child) => ListView.builder(
itemCount: mealsList.eatenMeals.length,
itemBuilder: (ctx, index) =>
DailyEaten(mealsList.eatenMeals[index]),
),
);
},
),
),
],
);
}
as you can see there is nothing in my build method , and I've used Consumer to avoid this loop , but still build method getting rebuild , would you explain with code snippets I appreciate it
Upvotes: 0
Reputation: 891
It is because calling notifyListeners
will rebuild the build
method(The one from which you have called Provider.of...
), which will create a loop.(The build
method call the future and notifyListener
will rebuild the build
method, and this process continues for ever).
To prevent this, provide another argument to the of
method: listen: false
Provider.of<EatenMeals>(context, listen: false).getServerMeals(currentUser.username, now);
This will prevent the build
method to rebuild.
Upvotes: 2
Reputation: 77304
The problem is that you are creating your future in your build method.
That means on every build, you create this future again.
That is a minor nuisance and a bug in your program, until you also add that the future itself triggers a rebuild, which means it will run, trigger a rebuild, the rebuild will wait for a new future, that will run, trigger a rebuild, create yet again a new future... you get it. It's an endless circle of running a future only to rebuild and run it again.
You have to create your Future outside of the build method. The build method can be triggered many times. Only reference a Future<> type variable in your build method and assign that variable in another method, maybe init or in some setState call when someone clicks a button.
Upvotes: 2