setState 是不是会在颤动中为屏幕重建整个小部件树,以及它与其他状态管理相比如何

Posted

技术标签:

【中文标题】setState 是不是会在颤动中为屏幕重建整个小部件树,以及它与其他状态管理相比如何【英文标题】:Does setState rebuild the whole widget tree for a screen in flutter and how does it compare with other State managementsetState 是否会在颤动中为屏幕重建整个小部件树,以及它与其他状态管理相比如何 【发布时间】:2020-10-31 05:20:33 【问题描述】:

我有点困惑,我最近一直在研究 Flutter 的状态管理,我想知道如果将自定义有状态小部件放置在无状态小部件中会发生什么,假设 widgetA(父级)是无状态小部件并且它有一个子 WidgetB 是有状态小部件,另一个子 WidgetC 是无状态小部件。

现在我的问题是:

如果从 widgetB 调用 setState(),是否会重建 WidgetA、B 和 C? 这与使用不同的状态管理技术(如状态提供程序、流构建器或 Bloc)相比如何? 何时使用 setState()? 结合多种状态管理技术是否明智?

如果您有可以帮助我理解的外部链接或资源,请提供

【问题讨论】:

【参考方案1】:

如果我说错了,请有人纠正我。

按顺序回答您的问题:

    如果您在WidgetB 上调用setState(),它会重建自己和它的后代,无论它们是Stateless 还是Stateful 小部件。

    使用 BLoC 方法,大多数时候可以选择使用Stateful WidgetssetState() 来管理状态。在这种方法中,您将使用 UI 中的events,它将在您的 BLoC 中转换为“状态”。此状态将被传递到流中。您的UI 将使用StreamBuilders 重建自己,每次他们在他们正在收听的 Stream 上收听一个新值。这将触发StreamBuilder 重建自身及其后代。

    如果您使用BLoCProvider + Streams,我建议您避免使用setState()StatefulWidgets,可能会有一些例外情况,例如UI 内容,例如。动画。

    BLoC 是一种与Provider package 相得益彰的设计方法。 BLoC package 甚至在内部使用Provider

P.S.:BLoC 是一种架构模式,用于管理应用程序的数据和状态。 Provider 只是 Inherited Widgets 的包装器,它有助于在整个 Widget 树中公开数据,而不是架构模式。

使用provider 包管理状态的架构模式解决方案的其他示例是MobX

【讨论】:

第4条中,“BLoC包甚至内部使用了Provider。”,这可能会让人认为bloc包使用provider来处理状态;虽然不是这样,它只使用提供者为小部件树提供一个块。 @AliAlizadeh 刚刚添加了此评论以使其更清晰【参考方案2】:

setState() 将调用 build() 方法并使用小部件树进行重建(在底层使用 Flutter 优化),如果您只想构建一部分,则有一个替代方案:创建一个包含您想要的更改的 Provider反映在 UI 中,并用 Consumer 包装该小部件 - 当您从 Provider 调用 notifyListener() 时,只有该小部件将重建。

例如:

 child: Consumer<MessageIconStateProvider>(
        builder: (context, messageIconProvider, child) 
          return Container(
            height: 40,
            child: messageIconProvider.isShowMessageIcon
                ? Icon(
              Icons.send,
              size: 24,
              color: Colors.white,
            )
                : Icon(
              Icons.mic_outlined,
              size: 24,
              color: Colors.white,
            ),
          );
        
    )

提供者:

 import 'package:flutter/material.dart';

class MessageIconStateProvider with ChangeNotifier 
  var isShowMessageIcon = true;
  
  void setIconToMessage(bool setIconToMessage)
    if(setIconToMessage != isShowMessageIcon) 
      isShowMessageIcon = setIconToMessage;
      notifyListeners();
    
  



别忘了在你的 main.dart 文件中定义它:

    class MyApp extends StatelessWidget 
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) 
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => MessageIconStateProvider()),
      ],...

【讨论】:

当你说“只有那个 Widget 会重建”是指只有那个 Widget(而不是任何后代 Widget)还是“只有那个节点以下的 Widget 树”?

以上是关于setState 是不是会在颤动中为屏幕重建整个小部件树,以及它与其他状态管理相比如何的主要内容,如果未能解决你的问题,请参考以下文章

Provider 和 setstate 哪个更贵?

每 5 秒更新一次文本小部件,而不在颤动中使用“setstate()”

如何在颤动中为整个应用程序设置文本颜色主题

Flutter - setState不使用新数据

如何在颤动中为 CachedNetworkImage 编写小部件测试

Flutter - setState 不更新内部有状态小部件