InheritedWidget(数据共享)

InheritedWidget简介

Flutter中的InheritedWidget是一个抽象类,是一个非常重要的一个功能型组件,它允许开发者高效地沿 Widget树向下传播数据,而不需要在父Widget把数据通过子Widget的构造方法逐个传递给子Widget。当然我们还可以创建一个父类,同时把数据保存到父类中,让所有的需要获取此数据的Widget都继承上面定义的父类;但是我们必须编写大量样板代码,我们还为每个Widget创建了依赖关系(因为Dart是单继承,就不能继承其他的类了),这不是一个好的做法。比如我们在应用的根Widget中通过InheritedWidget共享了一个数据,那么我们便可以在任意子Widget中来获取该共享的数据!这个特性在一些需要在整个 widget 树中共享数据的场景中非常方便!如Flutter SDK中正是通过InheritedWidget来共享应用主题(Theme)和 Locale (当前语言环境)信息的。

InheritedWidget和React中的context功能类似,逐级传递数据的同时,它们也能实现组件跨级传递数据。InheritedWidget在Flutter的作用在Android的UI开发中没有与之对应的类。 任何子Widget都可以获取到父InheritedWidget的数据。如下图所示:

InheritedWidget定义

实现InheritedWidget

scala 复制代码
class MyInheritedWidget extends InheritedWidget {
  final int data;
  
  const MyInheritedWidget({
    super.key,
    required this.data,
    required super.child,
  });

  @override
  bool updateShouldNotify(covariant MyInheritedWidget oldWidget) {
    return oldWidget.data != data;
  }

  static MyInheritedWidget? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
  }
}
  1. 首先,创建一个继承InheritedWidget的子类(如MyInheritedWidget),类里面的数据data限定为final,表示不可变每次更新数据每次都需要重新创建,构造函数中需要传递子Widget。
  2. 再次,重写updateShouldNotify方法。每当InheritedWidget中的数据发生变化时,都会调用此方法。如果此方法返回 true,则意味着将重建依赖于此InheritedWidget的子Widget。
  3. 最后,提供of的静态方法,返回MyInheritedWidget的对象。无论什么时候你想从MyInheritedWidget 获取数据,你都可以调用这个方法来获取这个MyInheritedWidget里面的数据。 BLoCProvider包都在幕后使用了InheritedWidgets。

InheritedWidget的使用

scala 复制代码
class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    //可以debug
    debugger(when: true);
    final inheritedWidget = MyInheritedWidget.of(context);
    final counter = inheritedWidget?.data ?? 0;

    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          const Text('You have pushed the button this many times:'),
          Text(
            '$counter',
            style: Theme.of(context).textTheme.headline4,
          ),
        ],
      ),
    );
  }
}
  1. 注意增加debugger(when: true)逻辑代码,可以进行单步调试,能够快速了解相应的逻辑。
  2. 当在子Widget(MyHomePage)的build方法中调用MyInheritedWidget的of的静态方法的时候,就相当于注册了一个MyInheritedWidget的监听器。当MyInheritedWidget数据变化的时候,此Widget(MyHomePage)会重新构建。 MyInheritedWidget.of()方法如何单步调试获取到MyInheritedWidget实例,如下图所示:

InheritedWidget适合使用场景

  1. 状态管理。管理全局或者分享的数据,比如用户身份认证状态,设置数据等等。
  2. 依赖注入:向Widget子树提供依赖项(例如服务或存储库)。
  3. 配置数据:将配置数据(例如本地化或应用程序范围的设置)传播到所有相关Widget。
  4. 主题或样式信息:自定义主题解决方案,其中应用程序的不同部分需要对主题更改做出反应。

InheritedWidget误用和滥用使用场景

  1. 过度重建:过度使用InheritedWidget或未正确实现updateShouldNotify会导致过度的Widget重建,从而导致性能问题。
  2. 过度复杂化简单状态:当更简单的解决方案(如StatefulWidget或ValueNotifier)就足够时,使用 InheritedWidget进行简单状态管理。
  3. 深度Widget树查找:严重依赖Widget树中的深度查找,这会使代码更难理解和维护。
  4. 全局状态管理:使用InheritedWidget进行复杂的全局状态管理,而不是使用更合适的解决方案,如 Provider、Riverpod(Google推荐使用) 或Bloc。
  5. context.dependOnInheritedWidgetOfExactType的不当使用:误用上下文查找方法,导致Widget树中出现意外的依赖关系和副作用。

总结

InheritedWidget是一个设计优良的功能型组件,作用是从父Widget高效地传递数据到子Widget。任何技术都有它使用场景的限制,有它能支持的场景,也有它所不及的场景。我们需要多试多练,多单步调试,多总结,多看它的源码和文档,定能解决现实中的技术问题。

致谢

希望文章对大家有所帮助,如果文章有所纰漏请不吝指教,大家共同进步。欢迎关注"技术蔡"的公众号,此公众号也是本作者的技术相关的公众号。

相关推荐
jcLee9516 小时前
Flutter/Dart:使用日志模块Logger Easier
flutter·log4j·dart·logger
tmacfrank17 小时前
Flutter 异步编程简述
flutter
tmacfrank17 小时前
Flutter 基础知识总结
flutter
叫我菜菜就好18 小时前
【Flutter_Web】Flutter编译Web第三篇(网络请求篇):dio如何改造方法,变成web之后数据如何处理
前端·网络·flutter
AiFlutter1 天前
Flutter-底部分享弹窗(showModalBottomSheet)
java·前端·flutter
m0_748247802 天前
Flutter Intl包使用指南:实现国际化和本地化
前端·javascript·flutter
迷雾漫步者2 天前
Flutter组件————PageView
flutter·跨平台·dart
迷雾漫步者2 天前
Flutter组件————FloatingActionButton
前端·flutter·dart
coder_pig3 天前
📝小记:Ubuntu 部署 Jenkins 打包 Flutter APK
flutter·ubuntu·jenkins
捡芝麻丢西瓜3 天前
flutter自学笔记5- dart 编码规范
flutter·dart