5

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

我通常使用从我的小部件直接从构建方法获取参数

  @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 小部件。

有什么建议吗?

4

4 回答 4

9

首先,请注意您可能确实想使用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 - 它不会处理值改变的场景。

因此,如果您的价值永远不会改变,您可以使用它来代替。

于 2019-07-23T18:08:59.807 回答
0

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

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

2、如果InheritedWidget的数据发生变化需要监听器重新渲染widget。我建议你将你的StatefulWidget内部包装成StatelessWidgetStatefulWidget的参数是从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();
  }
}
于 2019-07-24T03:24:37.993 回答
-1

我更喜欢解决方案,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();
  }
...
于 2019-07-23T15:38:43.143 回答
-2

您还可以在 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')),
          ],
        ));
      });
  }

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

于 2019-07-23T15:28:58.650 回答