Flutter:从子 StreamBuilder 更新有状态小部件

Posted

技术标签:

【中文标题】Flutter:从子 StreamBuilder 更新有状态小部件【英文标题】:Flutter: update stateful widget from child StreamBuilder 【发布时间】:2020-03-18 09:05:18 【问题描述】:

我已经编写了一些简化的代码,我希望 Firestore 数据的条件能够更新父窗口小部件。

我收到错误:在构建期间调用了 setState() 或 markNeedsBuild()。

如何从 StreamBuilder 中更新 myVar 的状态?更新 myVar 后,StreamBuilder 将不会被访问,而只会显示文本 Waiting...。

编辑:我更新了 myVar 以用作 Firestore 的文档 ID。为了澄清,我希望能够从 StreamBuilder 内部更新 StreamBuilder 的文档。换句话说,正如问题所说,从子 StreamBuilder 更新有状态小部件。

class MyWidget extends StatefulWidget 
  MyWidget(Key key)
      : super(key: key);

  @override
  _MyWidgetState createState() 
    return _MyWidgetState();
  


class _MyWidgetState extends State<MyWidget> 
  String myVar = "someID";

  @override
  Widget build(BuildContext context) 
    if (myVar == null) 
      // update myVar async, so that StreamBuilder will be re-rendered
      asyncFunctUpdate(myVar); // edit: finally got it to work if doing setState from asyncFuncUpdate(myvar).then(()=>setState)
      return Text("Waiting...");
    
    else
      return StreamBuilder<DocumentSnapshot>(
          stream: Firestore.instance
              .collection('myCollection')
              .document(myVar)
              .snapshots(),
          builder: (context, orderSnapshot) 
            if (!orderSnapshot.data.exists)
              setState(() 
                myVar = null;
              );
            else return Text(orderSnapshot);
          );
  

解决方法: 在我的情况下,像往常一样从 onPressed 函数返回来自 StreamBuilder 和 setState 的按钮更简单。

解决方案: 而不是从异步函数中执行 setState ,而是在 .then 子句中执行(参见上面的代码)

【问题讨论】:

您应该创建一个async 方法并从流生成器中调用它。比如:void setMyVar(String var) async setState(() myVar = var)。这应该在构建完成后运行。 @danypata 调用一个使用 async 关键字的函数,即使它不需要它也不会改变该函数的执行方式——它仍然会在 build 完成之前同步执行.至于实际解决方案,请查看 Artem 的回答。 确实使调用异步不起作用。它返回相同的错误。我更新了代码,因为它没有足够清楚地描述我的问题。 【参考方案1】:

一般来说,你不必做你现在正在做的事情。你可以做 return Text ("Waiting ...");立即无需调用 setState。在您的情况下,这是一个更好的决定。您响应来自流的事件并且必须根据当前状态返回内容

return StreamBuilder<DocumentSnapshot>(
      stream: Firestore.instance
          .collection('myCollection')
          .document('myDocument')
          .snapshots(),
      builder: (context, orderSnapshot) 
        if (!orderSnapshot.data.exists)
            return Text("Waiting...");
        else return Text(orderSnapshot);
      );

【讨论】:

嘿Artem,我的简化代码不够清楚,但在实际代码中有一个变量myDocument,它应该在显示“Waiting...”的情况下发生变化。我不希望 StreamBuilder 被“访问”,换句话说就是渲染。对不起,我不够清楚。【参考方案2】:

您可以使更新异步,就像将其放在匿名异步回调中一样

() async 
    setState();
();

您可以避免在该特定用例中出现状态,例如:

@override
  Widget build(BuildContext context) 
      return StreamBuilder<DocumentSnapshot>(
        stream: Firestore.instance
          .collection('myCollection')
          .document('myDocument')
          .snapshots(),
        builder: (context, orderSnapshot) 
          if (!orderSnapshot.data.exists) 
            return Text("Waiting...");
           else 
            return Text(orderSnapshot);
          
        );
  

【讨论】:

感谢您的回答,但我不得不更新我的问题,因为这个答案不能解决我的问题。 经过进一步调查,似乎它可以从 .then 子句而不是在异步函数内部执行 setState

以上是关于Flutter:从子 StreamBuilder 更新有状态小部件的主要内容,如果未能解决你的问题,请参考以下文章

来自一个 StreamBuilder 的 Flutter 快照显示在另一个 StreamBuilder 中

Flutter:Streambuilder - 关闭流

Flutter:StreamBuilder 快照——无数据

Flutter Streambuilder 正在复制项目

无法从 StreamBuilder (Flutter) 查询子集合

在页面 flutter,streambuilder,listview 之间导航时列表视图位置丢失