【问题标题】:How to set state from another widget?如何从另一个小部件设置状态?
【发布时间】:2018-10-30 00:20:00
【问题描述】:

我正在尝试从 Flutter 中的不同小部件更改状态。例如,在以下示例中,我在几秒钟后设置状态。

下面是代码:

class _MyAppState extends State<MyApp> {

  int number = 1;

  @override
  void initState() {
    super.initState();
    new Future.delayed(new Duration(seconds: 5)).then((_) {
      this.setState(() => number = 2);
      print("Changed");
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new Center(
        child: new FlatButton(
          color: Colors.blue,
          child: new Text("Next Page"),
          onPressed: () {
            Navigator.of(context).push(new MaterialPageRoute(
              builder: (BuildContext context) => new StatefulBuilder(builder: (BuildContext context, setState) =>new MySecondPage(number))
            ));
          },
        ),
      ),
    );
  }
}

我尝试使用InheritedWidget,但除非我将它包裹在我的顶级小部件周围,否则这将不起作用,这对于我正在尝试做的事情是不可行的(上面的代码是我所做的简化)我试图实现)。

关于在 Flutter 中实现这一目标的最佳方式有什么想法吗?

【问题讨论】:

标签: dart flutter


【解决方案1】:

实际上最有效的方法是在 Flutter 中使用 BLoC 包,并从小部件树的顶部实现它,这样所有继承的小部件都可以使用相同的 bloc。如果您以前使用过 Android - 它的工作方式类似于 Android 架构组件 - 您将数据和状态管理与 UI 分开 - 因此您无需在 UI 中设置状态,而是使用块来管理状态。因此,您可以设置和访问相同的数据 - 从任何从实现 bloc 的顶部小部件继承的小部件中设置和访问,对于更复杂的应用程序,它非常有用。

你可以在这里找到包:https://pub.dev/packages/flutter_bloc#-readme-tab-

写信:https://www.didierboelens.com/2018/08/reactive-programming-streams-bloc/

还有一个很棒的 youtube 教程https://www.youtube.com/watch?v=hTExlt1nJZI&list=PLB6lc7nQ1n4jCBkrirvVGr5b8rC95VAQ5&index=7

【讨论】:

    【解决方案2】:

    尽可能避免这种情况。它使这些小部件相互依赖,并且从长远来看会使事情变得更难维护。

    您可以做的是让两个小部件共享一个共同的Listenable 或类似的东西,例如Stream。然后小部件通过提交事件相互交互。

    为了更容易编写,您还可以将Listenable/Stream 分别与ValueListenableBuilder 和StreamBuilder 组合在一起,它们都为您完成了监听/更新部分。

    Listenable 的简单示例。

    class MyHomePage extends StatelessWidget {
      final number = new ValueNotifier(0);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: ValueListenableBuilder<int>(
            valueListenable: number,
            builder: (context, value, child) {
              return Center(
                child: RaisedButton(
                  onPressed: () {
                    number.value++;
                  },
                  child: MyWidget(number),
                ),
              );
            },
          ),
        );
      }
    }
    
    class MyWidget extends StatelessWidget {
      final ValueListenable<int> number;
    
      MyWidget(this.number);
    
      @override
      Widget build(BuildContext context) {
        return new Text(number.value.toString());
      }
    }
    

    请注意,我们如何在执行number.value++ 时自动更新 UI,而无需调用 setState。

    【讨论】:

    • 这看起来很有希望。我会在早上的第一件事上测试它!但我没有完全理解的一件事是 Flutter 如何知道重新渲染小部件。你能解释一下那部分吗?
    • AnimatedWidget/StreamBuilder 实际上包含重新渲染逻辑。它们都监听各自的对象,并在收到更改通知时调用 setstate,其中再次调用 builder。
    • 其背后的技巧是,在我的示例中,MyHomePage 实际上并没有更新。这是AnimatedWidget。
    • 啊哈,这就解释了!
    • @BramVanbilsen 如果您在小部件中嵌套了很多东西,而不是让ValueListenableBuilder 每次都重建所有内容,您应该查看child 参数,并使用它来显着优化渲染.阅读更多:docs.flutter.io/flutter/widgets/…
    猜你喜欢
    • 1970-01-01
    • 2020-07-31
    • 2020-09-10
    • 2021-02-16
    • 2021-07-20
    • 2021-09-11
    • 1970-01-01
    • 2019-12-17
    • 2021-12-26
    相关资源
    最近更新 更多