I am new to flutter and when I want to call my context in InitState it throws an error :
which is about
BuildContext.inheritFromWidgetOfExactType
but then I use did
I've found a significant difference between initState
and didChangeDependencies
:
initState
is called only once for a widget.didChangeDependencies
may be called multiple times per widget lifecycle (in my case it was called when the keyboard appears / disappears)you can still use context in initState() method, its hack buts works, all you need to do is sought of delay whatever you will need to execute that has context in it like so:
@override
void initState() {
Future.delayed(Duration.zero).then((_) {
// you code with context here
});
super.initState();
}
You cannot use
BuildContext.inheritFromWidgetOfExactType
from this method. However,didChangeDependencies
will be called immediately following this method, andBuildContext.inheritFromWidgetOfExactType
can be used there.
So you need to use BuildContext.inheritFromWidgetOfExactType
in didChangeDependencies
.
context
. That is why you have access to context outside build method. Regarding build(BuildContext context)
, build
method accepts context
from the parent widget. It means this parameter BuildContext context
is not current widget's context but its parent's context.
initState()
Called when new Widget is inserted into the tree.
The framework will call this method exactly once for each [State] object
it creates. This will be called once so perform work which required to be performed only once, but remember context
can't be used here, as widget state gets loaded only initState()
work is done.
Syntax:
@override
void initState() {
debugPrint('initState()');
super.initState();
}
didChangeDependencies()
Called when a dependency of this [State] object changes.
So, exactly How it gets called? as by the above definition, it looks like it will be called after state changes but how we come to know the state is changed?
Example:
The below example uses the Provider
state management mechanism to update the child widget from the parent widget. The Provider
has an attribute called updateShouldNotify
which decides whether to state is changed or not. If it's returning true
then only didChangeDependencies
gets called in ChildWidget
class.
updateShouldNotify is returning true by default internally, as it knows the state got changed. Then Why we need updateShouldNotify? it's need because if someone wants to update the state on a specific condition,
Eg: if UI required to show only even
values then we can add a condition like
updateShouldNotify: (oldValue, newValue) => newValue % 2 == 0,
Code Snippet:
class ParentWidget extends StatefulWidget {
ParentWidget({Key key, this.title}) : super(key: key);
final String title;
@override
_ParentWidgetState createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Life Cycle'),
),
body: Provider.value(
value: _counter,
updateShouldNotify: (oldValue, newValue) => true,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Press Fab button to increase counter:',
),
ChildWidget()
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class ChildWidget extends StatefulWidget {
@override
_ChildWidgetState createState() => _ChildWidgetState();
}
class _ChildWidgetState extends State<ChildWidget> {
int _counter = 0;
@override
void initState() {
print('initState(), counter = $_counter');
super.initState();
}
@override
void didChangeDependencies() {
_counter = Provider.of<int>(context);
print('didChangeDependencies(), counter = $_counter');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
print('build(), counter = $_counter');
return Text(
'$_counter',
);
}
}
Output Logs:
I/flutter ( 3779): didChangeDependencies(), counter = 1
I/flutter ( 3779): build(), counter = 1
For detail explanation:
https://medium.com/@jitsm555/differentiate-between-didchangedependencies-and-initstate-f98a8ae43164?sk=47b8dda310f307865d8d3873966a9f4f
Context of a state is available to us from the moment the State loads its dependencies.
At the time build is called, context is available to us and is passed as an argument.
Now moving on, initstate is called before the state loads its dependencies and for that reason no context is available and you get an error for that if u use context in initstate. However didChangeDependencies is called just few moments after the state loads its dependencies and context is available at this moment so here you can use context.
However both of them are called before build is called. Only difference is that one is called before the state loads its dependencies and other is called a few moments after the state loads its dependencies.
Called when a dependency of this State object changes.
For example, if the previous call to build referenced an InheritedWidget that later changed, the framework would call this method to notify this object about the change.
This method is also called immediately after initState. It is safe to call BuildContext.dependOnInheritedWidgetOfExactType from this method.
In fact Subclasses rarely override this method because the framework always calls build after a dependency changes. Some subclasses do override this method because they need to do some expensive work (e.g., network fetches) when their dependencies change, and that work would be too expensive to do for every build.