【问题标题】:Can I use setState for just one widget rather than whole page?我可以将 setState 仅用于一个小部件而不是整个页面吗?
【发布时间】:2020-06-04 22:35:59
【问题描述】:

我有一个 Future,它从我的 Cloud Firestore 数据库中获取一个值,并在我的应用程序正文中显示一个图标。如果数据库中的值发生更改,则图标会更新。我一直在使用 setState 来重建我的小部件树,并且效果很好 - 该应用程序几乎可以立即对我的 Cloud Firestore 数据库中的更改做出反应。这很棒!代码:

Future<void> takenSurvey2() async {
 final sn = await Firestore.instance
 .collection('Controller')
      .document('Current Survey')
      .get();
 surveyName2 = sn['cs'];
 final snapShot = await Firestore.instance
 .collection('$surveyName2' + '_entrants')
      .document(userid)
      .get();
 if (snapShot.exists) {
 takenSurvey = true;
  } else {
 takenSurvey = false;
  }
  setState(() {});
}

并且显示图标的位置是这样编码的(在堆栈中):

Positioned(
    right: 30,
    top: 20,
    child: FutureBuilder(
        future: takenSurvey2(),
        builder: (context, snapshot) {
 if (takenSurvey == false) {
 return Icon(
              Foundation.burst_new,
              size: 48,
              color: Color(0xff303841),
            );
          } else if (takenSurvey == true) {
 return Icon(
              Foundation.check,
              size: 48,
              color: Color(0xff303841),
            );
          } else
            return Container();
        })),

但是,我使用“admob_flutter”包在我的 AdMob 广告中添加了,因为 setState 似乎一直在运行,所以广告无法加载 - 我只看到一个闪烁的框。如果我从上面的代码中删除 setState,广告会加载,但当 Cloud Firestore 中的值发生变化时,我的应用中的图标不会更新。

如何从 setState 中排除我的 admob_flutter 小部件,或者仅使用 setState(或其他东西)仅更新我的 FutureBuilder 小部件?我想以一种限制 Cloud Firestore 调用次数的方式这样做,但这不是必需的。

我尝试过使用嵌套条件逻辑,但它似乎不起作用!

谢谢!

【问题讨论】:

  • tldr:你知道如何使用provider吗?如果是,您可以使用消费者,如果不是,您可以尝试解构您的小部件,只需将其移动到另一个有状态的小部件并从父小部件调用它
  • 是的,您可以,使用ConsumerSelector 与提供者:pub.dev/packages/provider,或者您可以将较小的小部件分成StatefulWidget

标签: flutter dart google-cloud-firestore


【解决方案1】:

我可以建议你使用ValueNotifier,如果你想操作简单的数据,比如在这种情况下是一个布尔值,这个小部件可以是完美的。您也可以使用void function 而不是future,如下所示:

  // Add a ValueNotifier for a single value
  final ValueNotifier<bool> _takenSurvey = ValueNotifier(null);

  void takenSurvey2() async {
    final sn = await Firestore.instance
        .collection('Controller')
        .document('Current Survey')
        .get();
    surveyName2 = sn['cs'];
    final snapShot = await Firestore.instance
        .collection('$surveyName2' + '_entrants')
        .document(userid)
        .get();
    if (snapShot.exists) {
      // Update the value of the ValueNotifier 
      _takenSurvey.value = true;
    } else {
      _takenSurvey.value = false;
    }
  }

要监听该值的变化,请使用ValueListenableBuilder

Positioned(
  right: 30,
  top: 20,
  child: ValueListenableBuilder(
    valueListenable: _takenSurvey,
    builder: (context, takenSurvey, child) {
      if(takenSurvey == null){
        return Container();
      }
      else{
        if (takenSurvey == false) {
          return Icon(
            Foundation.burst_new,
            size: 48,
            color: Color(0xff303841),
          );
        } else {
          return Icon(
            Foundation.check,
            size: 48,
            color: Color(0xff303841),
          );
        } 
      }
    },
  ),
)

希望对你有帮助。

【讨论】:

  • 谢谢你 - 我仍然有一个问题,即如果不在“takenSurvey2”中运行“setState”,它就不会自动更新。我已经使用了您提供的确切代码,但我仍然遇到问题:/
  • 可能问题出在小部件树的上一级,您能分享更多代码吗?检查正在发生的事情会很有帮助。
  • 当然,我已经把它放在这里了 - link
  • 太好了,您在FutureBuilder 中使用了两次takenSurvey2(),在onClick 方法中使用了另一次,所以我真的建议您使用void function 而不是Future ,其他情况下,您可以使用Future&lt;bool&gt; 而不是Future&lt;void&gt;,返回takenSurvey 值并像snapshot.value 一样使用它。
【解决方案2】:

您可以为此使用StatefulBuilderStatefulBuilder 给你一个单独的setState 作为构建器参数,而setState 只会影响构建器下的状态。

Flutter API 文档在 https://api.flutter.dev/flutter/widgets/StatefulBuilder-class.html 上有一个非常清晰的示例。

【讨论】:

    猜你喜欢
    • 2022-09-28
    • 1970-01-01
    • 2011-06-24
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 2011-10-19
    • 2018-06-08
    相关资源
    最近更新 更多