在 initState 中获取 InheritedWidget 参数
Posted
技术标签:
【中文标题】在 initState 中获取 InheritedWidget 参数【英文标题】:Get InheritedWidget parameter in initState 【发布时间】:2019-12-01 16:34:57 【问题描述】:我需要一些帮助来了解如何从继承的小部件中获取数据。
我通常使用
直接从构建方法中从我的小部件中获取参数 @override
Widget build(BuildContext context)
//THIS METHOD
var data = StateContainer.of(context).data;
return Container(child:Text("$data.parameter"));
但由于还没有 buildContext,因此无法从 initState 调用此方法。
我需要在 initState 方法中具有该参数(我在其中调用从服务器获取的数据,并且我需要将该数据传递给我的函数),那么,我应该怎么做呢?
@override
void initState()
otherData = fetchData(data);
super.initState();
我尝试使用 didChangeDipendencies(),但每次重建视图(从屏幕弹出等)时都会调用它,所以它不是我想要使用的,也不是 FutureBuilder 小部件。
有什么建议吗?
【问题讨论】:
【参考方案1】:首先,请注意您可能确实想要使用didChangeDependencies
。但是你不能在没有任何检查的情况下就在那里打电话。您需要先将其包装在 if
中。
典型的didChangeDependencies
实现应该类似于:
Foo foo;
@override
void didChangeDependencies()
super.didChangeDependencies();
final foo = Foo.of(context);
if (this.foo != foo)
this.foo = foo;
foo.doSomething();
使用这样的代码,doSomething
将仅在foo
更改时执行。
或者,如果您很懒惰并且确定您的对象永远不会改变,那么还有另一种解决方案。
获取InheritedWidget,常用的方法是:
BuildContext context;
InheritedWidget foo = context.inheritFromWidgetOfExactType(Foo);
而在initState
内部不能调用的正是这个方法。
但是还有另一种方法可以做同样的事情:
BuildContext context;
InheritedWidget foo = context.ancestorInheritedElementForWidgetOfExactType(Foo)?.widget;
转折是:
- 这个方法可以在initState
里面调用
- 它不会处理值改变的场景。
所以如果你的值永远不会改变,你可以使用它来代替。
【讨论】:
【参考方案2】:1、如果你只需要InheritedWidget作为Widget参数的Provider。 您可以在 initState 上使用如下:
@override
void initState()
super.initState();
var data = context.ancestorInheritedElementForWidgetOfExactType(type)?.widget;
2、当InheritedWidget的数据发生变化时,如果需要监听器重新渲染widget。我建议您将 StatefulWidget 内部人员包装为 StatelessWidget, StatefulWidget的参数是从StatelessWidget传过来的,当InheritedWidget改变数据时,会通知StatelessWidget,在StatefulWidget 我们将在 didChangeDependencies 上获得更改,您可以刷新数据。 这是代码指南:
class WrapperDemoWidget extends StatelessWidget
@override
Widget build(BuildContext context)
DemoData data = StateContainer.of(context).data;
return Container();
class ImplementWidget extends StatefulWidget
DemoData data;
ImplementWidget(this.data);
@override
_ImplementWidgetState createState() => _ImplementWidgetState();
class _ImplementWidgetState extends State<ImplementWidget>
@override
void initState()
super.initState();
//TODO Do sth with widget.data
@override
void didChangeDependencies()
super.didChangeDependencies();
//TODO Do change with widget.data
@override
Widget build(BuildContext context)
return Container();
【讨论】:
【参考方案3】:我更喜欢didChangeDependencies
的解决方案,因为Future.delayed
解决方案有点hack,看起来不专业且不健康。但是,它开箱即用。
这是我更喜欢的解决方案:
class _MyAppState extends State<MyApp>
bool isDataLoaded = false;
@override
void didChangeDependencies()
if (!isDataLoaded)
otherData = fetchData(data).then((_)
this.isDataLoaded = true;
);
super.didChangeDependencies();
...
【讨论】:
虽然比Future.delayed
更好,但布尔值错过了生命周期的要点,即处理数据更改的场景。【参考方案4】:
您还可以在 initState 中获取上下文,尝试使用持续时间为零的未来。你可以找到一些例子here
void initState()
super.initState();
Future.delayed(Duration.zero,()
//use context here
showDialog(context: context, builder: (context) => AlertDialog(
content: Column(
children: <Widget>[
Text('@todo')
],
),
actions: <Widget>[
FlatButton(onPressed: ()
Navigator.pop(context);
, child: Text('OK')),
],
));
);
我使用它来使用继承的小部件制作加载屏幕并避免一些全局变量
【讨论】:
以上是关于在 initState 中获取 InheritedWidget 参数的主要内容,如果未能解决你的问题,请参考以下文章
在构建之前使用 initState 从函数中获取值并插入到变量中
Flutter:异步任务在“initState()”中无法按预期工作