在 initState 中获取 InheritedWidget 参数

Get InheritedWidget parameter in initState

我需要一些帮助来了解如何从继承的小部件获取数据。

我通常使用

直接从构建方法中获取小部件的参数
  @override
  Widget build(BuildContext context) {    
   //THIS METHOD
   var data = StateContainer.of(context).data;

   return Container(child:Text("${data.parameter}"));
  }

但是这个方法不能从 initState 调用,因为还没有 buildContext。

我需要在 initState 方法中包含该参数(我在其中调用从服务器获取数据,我需要将该数据传递给我的函数),那么,我应该怎么做?

@override
void initState() {
 otherData = fetchData(data);
 super.initState();
}

我尝试使用 didChangeDipendencies() 但每次重建视图(从屏幕弹出等)时都会调用它,所以它不是我想要使用的,也不是 FutureBuilder 小部件。

有什么建议吗?

您还可以在 initState 中获取上下文,尝试使用持续时间为零的未来。你可以找到一些例子

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')),
          ],
        ));
      });
  }

我用它来使用继承的小部件制作加载屏幕并避免一些全局变量

我更喜欢 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();
  }
...

首先,请注意您可能 想要使用 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 - 它不会处理值更改的情况。

因此,如果您的值永远不会改变,您可以改用它。

1、如果你只需要InheritedWidget作为Widget的参数提供者。 您可以在 initState 上使用,如下所示:

@override
void initState() {
    super.initState();
    var data = context.ancestorInheritedElementForWidgetOfExactType(type)?.widget;
}

2、当InheritedWidget数据变化时,如果需要监听re-renderwidget。我建议你把你的 StatefulWidget insider 包装成 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();
  }
}