I’m trying to use FutureBuilder inside a Stateless widget. The data is rendered properly, however I do face an issue "setState() or markNeedsBuild() called during build.". I’ve tried converting it to the Stateful widget and initializing future inside onInit() method but I acutally get the same error. Please find my code for both stateless and statefull widgets.
Stateless Widget
class DoctorsListWidget extends StatelessWidget {
const DoctorsListWidget({Key? key}) : super(key: key);
Future<void> _refreshDoctors(BuildContext context) async {
await Provider.of<DoctorsProvider>(context, listen: false).getDoctors();
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _refreshDoctors(context),
builder: (context, snapshot) =>
snapshot.connectionState == ConnectionState.waiting
? Center(
child: CircularProgressIndicator(),
)
: RefreshIndicator(
onRefresh: () => _refreshDoctors(context),
child: Consumer<DoctorsProvider>(
builder: (context, doctorsProvider, _) => Container(
height: 400,
child: Padding(
padding: EdgeInsets.all(10),
child: ListView.builder(
itemBuilder: (_, i) => Column(
children: <Widget>[
DoctorItemWidget(
doctorsProvider.doctors[i].name,
doctorsProvider.doctors[i].surname,
doctorsProvider.doctors[i].spec,
true),
],
),
itemCount: doctorsProvider.doctors.length,
),
),
),
),
),
);
}
}type here
Stateful widget
class DoctorsStatefulListWidget extends StatefulWidget {
const DoctorsStatefulListWidget({Key? key}) : super(key: key);
@override
_DoctorsStatefulListWidgetState createState() =>
_DoctorsStatefulListWidgetState();
}
class _DoctorsStatefulListWidgetState extends State<DoctorsStatefulListWidget> {
Future? _future;
@override
void initState() {
super.initState();
_future = Provider.of<DoctorsProvider>(context, listen: false).getDoctors();
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _future,
builder: (context, snapshot) =>
snapshot.connectionState == ConnectionState.waiting
? Center(
child: CircularProgressIndicator(),
)
: RefreshIndicator(
onRefresh: () => _refreshDoctors(),
child: Consumer<DoctorsProvider>(
builder: (context, doctorsProvider, _) => Container(
height: 400,
child: Padding(
padding: EdgeInsets.all(10),
child: ListView.builder(
itemBuilder: (_, i) => Column(
children: <Widget>[
DoctorItemWidget(
doctorsProvider.doctors[i].name,
doctorsProvider.doctors[i].surname,
doctorsProvider.doctors[i].spec,
true),
],
),
itemCount: doctorsProvider.doctors.length,
),
),
),
),
),
);
}
Future<void> _refreshDoctors() async {
await Provider.of<DoctorsProvider>(context, listen: false).getDoctors();
}
}
Doctors Provider
class DoctorsProvider with ChangeNotifier {
List<DoctorProvider> _doctors = [];
DoctorsProvider(this._doctors);
List<DoctorProvider> get doctors {
return [..._doctors];
}
Future<void> getDoctors() async {
_doctors = MockedDoctorsProvider().doctors;
notifyListeners();
}
}```
Both of the widgets throw the same error when running.
======== Exception caught by foundation library ====================================================
The following assertion was thrown while dispatching notifications for DoctorsProvider:
setState() or markNeedsBuild() called during build.
This _InheritedProviderScope<DoctorsProvider?> 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<DoctorsProvider?>“`
Do I get the infinite loop somewhere although using Consumer?
Looking forward for your help!
I’ve tried converting the stateless widget to stateful one but the same error is thrown.
2
Answers
I'm not sure why but it looks that when using
FutureBuilder
, thegetDoctors()
method inside a provider should not call thenotifyListeners()
method. The view is rendered correctly without calling thenotifyListeners()
and the error no longer occurs.Try the following: