我是新手,要在InitState中调用上下文时会抛出错误:
这是关于
doc.getElementsByTagName("input")(0).value = "My value"
但是然后我使用didChangeDependencies,它可以正常工作。
现在我有2个问题:
1-为什么我们不能在initState中调用上下文,但是didChangeDependencies没有问题?
(因为我在官方文档BuildContext.inheritFromWidgetOfExactType
中读过,
并且它们都将在build方法之前被调用。 )
2-为什么我们可以在build方法之外访问上下文(因为那里有This method is also called immediately after [initState]
,我们可以使用我们的上下文,但是在didChangeDependencies中,我们没有类似build(BuildContext context)
的东西,所以从哪里开始可以调用上下文来使用它)?
答案 0 :(得分:1)
从状态加载其依赖项之时起,我们就可以使用状态上下文。
在调用build时,上下文可供我们使用,并作为参数传递。
现在继续前进, 在状态加载其依赖项之前会调用initstate,因此,没有上下文可用,并且如果您在initstate中使用上下文,则会收到一个错误消息。 但是,在状态加载其依赖项后不久,就会调用didChangeDependencies,此时可以使用上下文,因此您可以在这里使用上下文。
但是在调用build之前都调用了它们。 唯一的区别是,一个在状态加载其依赖项之前被调用,而另一个在状态加载其依赖项之后被调用。
答案 1 :(得分:1)
当此State对象的依赖项更改时调用。
例如,如果先前的build引用引用了后来更改的 InheritedWidget ,则框架将调用此方法以将该更改通知此对象。
在 initState 之后也立即调用此方法。从此方法调用 BuildContext.dependOnInheritedWidgetOfExactType 是安全的。
实际上,子类很少重写此方法,因为框架总是在依赖项更改后调用build。一些子类确实重写了此方法,因为当它们的依赖项发生变化时,它们需要做一些昂贵的工作(例如,网络获取),并且对于每个构建而言,所做的工作都太昂贵了。
答案 2 :(得分:1)
initState()
在将新的Widget插入树中时调用。
框架将为每个[State]对象仅调用一次此方法
它创建。这将被调用一次,因此执行只需要执行一次的工作,但是请记住,context
在这里不能使用,因为窗口小部件状态仅被加载initState()
。
语法:
@override
void initState() {
debugPrint('initState()');
super.initState();
}
didChangeDependencies()
在此[State]对象的依赖项更改时调用。
那么,就像上面的定义一样,它是如何被调用的?,它看起来像在状态改变后将被调用,但是我们如何知道状态被改变了?
示例:
下面的示例使用Provider
状态管理机制从父窗口小部件更新子窗口小部件。 Provider
具有一个称为updateShouldNotify
的属性,该属性决定状态是否被更改。如果返回的是true
,则didChangeDependencies
类中只会调用ChildWidget
。
updateShouldNotify在内部默认情况下返回true,因为它知道状态已更改。 然后我们为什么需要updateShouldNotify?,因为有人要在特定条件下更新状态,
例如:如果用户界面只需要显示even
值,那么我们可以添加条件
updateShouldNotify: (oldValue, newValue) => newValue % 2 == 0,
代码段:
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',
);
}
}
输出日志:
I/flutter ( 3779): didChangeDependencies(), counter = 1
I/flutter ( 3779): build(), counter = 1
有关详细说明:
答案 3 :(得分:0)
您不能通过此方法使用
BuildContext.inheritFromWidgetOfExactType
。但是,didChangeDependencies
将在此方法之后立即调用,并且BuildContext.inheritFromWidgetOfExactType
可以在此处使用。
因此,您需要在BuildContext.inheritFromWidgetOfExactType
中使用didChangeDependencies
。
context
。这就是为什么您可以在build方法之外访问上下文。 关于build(BuildContext context)
,build
方法从父窗口小部件接受context
。这表示此参数BuildContext context
不是当前小部件的上下文,而是其父级的上下文。
答案 4 :(得分:0)
我发现initState
和didChangeDependencies
之间存在显着差异:
initState
仅对窗口小部件调用一次。didChangeDependencies
可能被多次称为多次(在我的情况下,它是在键盘出现/消失时被调用的)答案 5 :(得分:0)
您仍然可以在initState()方法中使用上下文,它的hacks可以正常工作,您需要做的就是寻求延迟,无论您需要执行的是什么,都需要延迟,就像这样:
@override
void initState() {
Future.delayed(Duration.zero).then((_) {
// you code with context here
});
super.initState();
}
答案 6 :(得分:0)
这是一个补充答案,显示了 OP 所描述的内容。
State
的 StatefulWidget
类具有 context
属性。此构建上下文首先在 didChangeDependencies
中可用。尝试在 context
中使用 initState
会导致错误。
class HomeWidget extends StatefulWidget {
const HomeWidget({Key key}) : super(key: key);
@override
_HomeWidgetState createState() => _HomeWidgetState();
}
class _HomeWidgetState extends State<HomeWidget> {
@override
void initState() {
print('initState');
// print(Theme.of(context)); // ERROR!
super.initState();
}
@override
void didChangeDependencies() {
print('didChangeDependencies');
print(Theme.of(context)); // OK
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
print('build');
print(Theme.of(context)); // OK
return Container();
}
}
运行,按以下顺序给出打印语句:
initState
didChangeDependencies
ThemeData#93b06
build
ThemeData#93b06
答案 7 :(得分:-1)
答案是here
不应从小部件构造函数或State.initState方法中调用此方法,因为如果继承的值发生更改,则不会再次调用这些方法。为了确保在继承值更改时小部件能够正确更新自身,请仅从构建方法,布局和绘制回调,或从State.didChangeDependencies中调用(直接或间接)。