Extract from framework.dart
/// [State] objects have the following lifecycle:
///
/// * The framework creates a [State] object by calling
/// [StatefulWidget.createState].
/// * The newly created [State] object is associated with a [BuildContext].
/// This association is permanent: the [State] object will never change its
/// [BuildContext]. However, the [BuildContext] itself can be moved around
/// the tree along with its subtree. At this point, the [State] object is
/// considered [mounted].
/// * The framework calls [initState]. Subclasses of [State] should override
/// [initState] to perform one-time initialization that depends on the
/// [BuildContext] or the widget, which are available as the [context] and
/// [widget] properties, respectively, when the [initState] method is
/// called.
Above is a extract from framework.dart
file which explains the lifecycle of a state object.
In this it says that initstate()
can be used to initialize context. But when i try to run the code given below, It gives an error which says that when initstate()
is called the context is not available, which to me seems is in contradiction to what the framework.dart says in the lifecycle section. Can anyone explain this.
Code
@override
void initState() {
// TODO: implement initState
super.initState();
if (!_initial) {
final arguments =
ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>;
categoryTitle = arguments['item'];
categoryId = arguments['id'];
categoryMeals = dummyMeals.where((meal) {
return meal.categories.contains(categoryId);
}).toList();
}
_initial = true;
}
Error Message
The following assertion was thrown building Builder:
dependOnInheritedWidgetOfExactType<_ModalScopeStatus>() or dependOnInheritedElement() was called before _MealScreenState.initState() completed.
When an inherited widget changes, for example if the value of Theme.of() changes, its dependent widgets are rebuilt. If the dependent widget's reference to the inherited widget is in a constructor or an initState() method, then the rebuilt dependent widget will not reflect the changes in the inherited widget.
Typically references to inherited widgets should occur in widget build() methods. Alternatively, initialization based on inherited widgets can be placed in the didChangeDependencies method, which is called after initState and whenever the dependencies change thereafter.
CodePudding user response:
You should use this
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
--- your code here ---
});
in your initState();
You are facing that issue because you are trying to use a context that hasn't finished yet to build. The addPostFrameCallback
execute your code after all the Widget is built.
CodePudding user response:
initState
runs once before the widget is inserted into the widget tree. The context
is available at that time, but the problem with your code is that in initState
you are relying on something that can change after the widget is inserted.
The solution is to move this logic into an overridden didChangeDependencies
method, which will be called not only once, but every time the dependencies changed:
@override
void didChangeDependencies() {
super.didChangeDependencies();
// put your logic from initState here
}
See this SO question for example for a detailed explanation.