So while learning Flutter, it seems that initState()
is not a place to use Providers as it does not yet have access to context
which must be passed. The way my instructor gets around this is to use the didChangeDependencies()
life-cycle hook in conjunction with a flag so that any code inside doesn't run more than once:
bool _isInit = true;
@override
void didChangeDependencies() {
if (_isInit) {
// Some provider code that gets/sets some state
}
_isInit = false;
super.didChangeDependencies();
}
This feels like a poor development experience to me. Is there no other way of running initialisation code within a Flutter Widget that has access to context
? Or are there any plans to introduce something more workable?
The only other way I have seen is using Future.delayed
which feels a bit "hacky":
@override
void initState() {
Future.delayed(Duration.zero).then(() {
// Some provider code that gets/sets some state
});
super.initState();
}
It's possible to schedule code to run at the end of the current frame. If scheduled within initState()
, it seems that the Widget is fully setup by the time the code is running.
To do so, you can use the addPostFrameCallback method of the SchedulerBinding
instance:
@override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) {
// Some provider code that gets/sets some state
})
}
You can also use WidgetsBinding.instance.addPostFrameCallback()
for this. They both behave the same for the purpose of running code once after the Widget has been built/loaded, but here is some more detail on the differences.
Note: be sure to import the file needed for SchedulerBinding:
import 'package:flutter/scheduler.dart';