flutter 获取initState中的InheritedWidget参数

klr1opcd  于 2023-04-22  发布在  Flutter
关注(0)|答案(5)|浏览(215)

我需要一些帮助,了解如何从继承的小部件获取数据。
我通常直接从我的小部件的build方法中获取参数

@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小部件。
有什么建议吗?

piah890a

piah890a1#

首先,请注意,您可能确实想使用didChangeDependencies。但您不能在没有任何检查的情况下直接调用。您需要首先将其 Package 在if中。
典型的didChangeDependencies实现应该类似于:

Foo foo;

@override
void didChangeDependencies() {
  super.didChangeDependencies();
  final foo = Foo.of(context);
  if (this.foo != foo) {
    this.foo = foo;
    foo.doSomething();
  }
}

使用这样的代码,当foo发生变化时,doSomething执行。
或者,如果你很懒,并且确信你的对象永远不会改变,还有另一种解决方案。
要获得InheritedWidget,通常使用的方法是:

BuildContext context;
InheritedWidget foo = context.inheritFromWidgetOfExactType(Foo);

并且在initState内部不能调用的就是这个方法。
但还有另一种方法可以做同样的事情:

BuildContext context;
InheritedWidget foo = context.ancestorInheritedElementForWidgetOfExactType(Foo)?.widget;

扭曲是:- 这个方法可以在initState内部调用-它不会处理值更改的情况。
所以如果你的值永远不会改变,你可以用它来代替。

d4so4syb

d4so4syb2#

1、如果只需要InheritedWidget作为Widget的参数Provider,可以在 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();
  }
}
bjg7j2ky

bjg7j2ky3#

我尝试了Remi的解决方案,但不知道ancestorInheritedElementForWidgetOfExactType方法现在是否已被弃用?但我可以找到它。
用这个代替:

BuildContext context;
InheritedWidget foo = context.findAncestorWidgetOfExactType<Foo>()?
xqnpmsa8

xqnpmsa84#

我更喜欢使用didChangeDependencies的解决方案,因为Future.delayed解决方案有点黑客,看起来不专业和不健康。然而,它可以开箱即用。
这是我更喜欢的解决方案:

class _MyAppState extends State<MyApp> {

    bool isDataLoaded = false;

    @override
  void didChangeDependencies() {
    if (!isDataLoaded) {
            otherData = fetchData(data).then((_){
                this.isDataLoaded = true;
            });
    }
    super.didChangeDependencies();
  }
...
w8ntj3qf

w8ntj3qf5#

您也可以在initState中获取上下文,尝试使用持续时间为零的future。

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

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

相关问题