I get the following error while using Provider in Flutter :
The following assertion was thrown while dispatching notifications for CampaignProvider: setState() or markNeedsBuild() called during build. This _InheritedProviderScope<CampaignProvider?> widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase. The widget on which setState() or markNeedsBuild() was called was: _InheritedProviderScope<CampaignProvider?> The widget which was currently being built when the offending call was made was: KeyedSubtree-[GlobalKey#a8154]
Here is my widget :
class CampaignsScreen extends StatefulWidget {
const CampaignsScreen({Key? key}) : super(key: key);
@override
State<CampaignsScreen> createState() => _CampaignsScreenState();
}
class _CampaignsScreenState extends State<CampaignsScreen> {
@override
void initState() {
super.initState();
context.read<CampaignProvider>().getCampaigns();
}
@override
Widget build(BuildContext context) {
List<Campaign> campaigns = context.watch<CampaignProvider>().campaigns;
return Scaffold(
appBar: AppBar(
title: const Text('Campagnes'),
),
body: Center(
child: ListView.builder(
itemCount: campaigns.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(campaigns[index].title),
subtitle: Text(campaigns[index].description),
);
},
),
),
);
}
}
And my provider:
class CampaignProvider with ChangeNotifier {
final CampaignService _campaignService = CampaignService();
List<Campaign> _campaigns = [];
List<Campaign> get campaigns {
return _campaigns;
}
void getCampaigns() {
_campaigns = _campaignService.getCampaigns();
notifyListeners();
}
}
It seems that I cannot use context.read() in initState(). But how can I call the method getCampaigns from my Provider class when the widget is building and listen for value changes so my screen can be updated ?
I tried to replace context.watch() by Consumer but I got the same error.
2
Answers
That’s because you’re refreshing the widget when this was not built yet.
You’ll need to wait until the first frame is loaded, like this:
Adding more context, as
jraufeisen
mentioned, it seems like your code is not using any async method,getCampaigns()
is not returning a Future, so in this case you can omit thenotifyListeners
and it will work.If your method
getCampaigns
returns a Future, thennotifyListeners
will work (or the solution I proposed first).You can use Future.delayed