【问题标题】:Get InheritedWidget parameter in initState在 initState 中获取 InheritedWidget 参数
【发布时间】: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 小部件。

有什么建议吗?

【问题讨论】:

    标签: flutter dart state inherited-widget


    【解决方案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();
      }
    }
    

    使用这样的代码,doSomethingfoo 更改时执行。


    或者,如果您很懒惰并且确定您的对象永远不会改变,那么还有另一种解决方案。

    获取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 内部人员包装为 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();
        }
      }
      

      【讨论】:

        【解决方案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')),
                  ],
                ));
              });
          }
        

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-10-09
          • 1970-01-01
          • 2018-09-02
          • 2020-07-11
          • 2019-07-28
          • 2020-10-08
          • 1970-01-01
          • 2019-10-04
          相关资源
          最近更新 更多