问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

啊哈,原来 InheritedWidget 是这个意思

创作时间:
作者:
@小白创作中心

啊哈,原来 InheritedWidget 是这个意思

引用
CSDN
1.
https://blog.csdn.net/mzxj7255/article/details/138339390

在Flutter开发中,状态管理是一个核心话题。InheritedWidget作为Flutter中最基础的状态管理工具之一,虽然使用频率很高,但其原理和使用细节往往容易被忽视。本文将深入探讨InheritedWidget的工作原理、使用方法及其优缺点,帮助开发者更好地理解和使用这一重要工具。

在开发Flutter应用过程中,状态管理是一个至关重要且经常讨论的话题。随着应用规模的扩大和复杂度的增加,有效地管理应用的状态也逐渐变得尤为关键。而InheritedWidget作为Flutter中最基础、最底层的状态管理工具之一,承担着传递数据、共享状态的重要责任,本篇将深入探讨InheritedWidget的原理、使用方法、在实际开发中的应用场景及它的优缺点。希望能帮助你更好的理解及使用InheritedWidget。

InheritedWidget在日常开发中使用的还是挺多的,或者说没有直接使用它,但MediaQuery.of(context)、Theme.of(context)这些经常用吧,还有Provider、Bloc这些状态管理的插件总用过吧,这些可以做到共享数据或者更新数据的原因,就是因为它们背后是InheritedWidget来实现的。

简单的来讲,InheritedWidget其实是就是一种跨widget共享数据的机制,比如在名A的widget中调用了.of(context)来获取数据,这个时候会将A注册为InheritedWidget的监听器,所以每当InheritedWidget中的值发生变化时,这个A就会被重建。

工作原理

其工作原理就是当一个Widget需要访问共享的数据时,它会通过context向上查找最近的父的InheritedWidget。如果找到了父的InheritedWidget,就会将从中获取共享数据。当共享数据发生变化时,InheritedWidget会通知其所有子Widget,并触发它们重建。子Widget在重建时会获取最新的共享数据,并根据新的数据状态更新自己的内容。下面一段代码看看InheritedWidget的用法。

class CustomColorWidget extends InheritedWidget {
  const CustomColorWidget({
    super.key,
    required super.child,
    required this.color,
    required this.onColorChange,
  });
  final Color color;
  final void Function() onColorChange;
  static CustomColorWidget? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<CustomColorWidget>();
  }
  @override
  bool updateShouldNotify(CustomColorWidget oldWidget) {
    return oldWidget.color != color;
  }
}

of方法

  • of方法是static,意味着不需要类的示例,可以直接使用类来调用。参数BuildContext则表示widget在widget tree中的位置。
  • of方法内部调用了context.dependOnInheritedWidgetOfExactType()方法。 此方法由Flutter框架提供,并从给定的BuildContext开始搜索CustomColorWidget类型的最近父widget,。
  • dependOnInheritedWidgetOfExactType()函数返回的是找到的CustomColorWidget,所以访问其属性或方法,如果没有找到匹配的小部件,则返回null。
    通过使用of方法,可以很方便地从widget tree中的任何点检索特定类型的最近父widget,而不需要手动遍历树。

updateShouldNotify方法

这是InheritedWidget文档的一段话,翻译过来:框架是否应该通知继承此小部件的小部件。当重建此小部件时,有时我们需要重建从此小部件继承的小部件,但有时则不需要。 例如,如果这个小部件保存的数据与oldWidget保存的数据相同,那么我们不需要重建继承oldWidget保存数据的小部件。框架通过使用先前占据树中此位置的小部件作为参数来调用此函数来区分这些情况。保证给定的小部件具有与此对象的runtimeType相同。

结合上面的代码例子来说,updateShouldNotify方法是重写父类的方法,用于是否需要向它的子类widget通知更新,其由Flutter框架自动调用,当前的实例的属性与先前(旧)实例的属性进行比较。如果比较结果为true,则意味着color属性已更改,并且将更改通知InheritedWidget的子类widget。

如何使用

这里实现一个当点击按钮改变InheritedWidget下子widget(也就是MyCardWidget)的背景颜色的demo。

class InheritedWidgetTestPage extends StatefulWidget {
  const InheritedWidgetTestPage({Key? key}) : super(key: key);
  @override
  State<InheritedWidgetTestPage> createState() =>
      _InheritedWidgetTestPageState();
}
class _InheritedWidgetTestPageState extends State<InheritedWidgetTestPage> {
  Color color = Colors.blue;
  @override
  Widget build(BuildContext context) {
    return CustomColorWidget(
      color: color,
      onColorChange: onColorChange,
      child: Scaffold(
        backgroundColor: Colors.white,
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              MyCardWidget(key: UniqueKey()),
              FilledButton(
                onPressed: () => onColorChange(),
                child: const Text("Change Color"),
              ),
            ],
          ),
        ),
      ),
    );
  }
  void onColorChange() {
    setState(() {
      color = Color.fromRGBO(Random().nextInt(256), Random().nextInt(256), Random().nextInt(256), 1);
    });
  }
}
class MyCardWidget extends StatelessWidget {
  const MyCardWidget({super.key});
  @override
  Widget build(BuildContext context) {
    return Container(
      color: CustomColorWidget.of(context)?.color ?? Colors.white,
      height: 200,
      width: 200,
    );
  }
}

这里可以看到,CustomColorWidget被作为父部件包裹着Scaffold,这样它的子widget也就是MyCardWidget就能够通过CustomColorWidget.of(context)?.color来访问color属性。当点击按钮时调用setState触发重新构建。由于CustomColorWidget是一个InheritedWidget,它的父widget会重建,将新的color值传递给MyCardWidget进行重新渲染。

来看看运行效果:

优点

  • 更加高效的数据共享:InheritedWidget提供了一种在widget tree中的多个widget之间共享数据的有效方法,而不需要显式的数据传递。 它避免了手动通过多个级别向小部件传递参数。
  • 自动更新InheritedWidget内部的widget:当InheritedWidget内的数据发生更改时,widget tree中的所有依赖这个InheritedWidget的都会自动更新。 也避免了跨widget手动跟踪和更新数据。
  • 全局可访问性:一旦将InheritedWidget放置在widget tree的根部,就可以从tree中的任何子的widget访问它的数据。 这提供了对共享数据的全局访问,不再需要显式传递数据。

缺点

  • 共享数据的范围有限:InheritedWidget共享的数据仅限于其下方的widget子树。 如果需要跨多个独立的widget树或跨不同的页面共享数据,仅InheritedWidget可能还不够,需要使用其他状态管理解决方案。
  • 有一定潜在的性能影响:将InheritedWidget用于大型且频繁更改的数据可能会影响性能。 当数据发生变化时,widget树中依赖于InheritedWidget的每个widget都会被重建,这可能会导致不必要的重建并影响应用程序性能。 因此,我们需要更加优化的状态管理方法。
  • 容易造成数据耦合:由于InheritedWidget共享的数据可由任何后代widget访问,因此不相关的widget之间可能存在耦合,意思就是一个子widget需要color,而另外一个需要text,但是color和text都存放在这两个widget父的InheritedWidget里面。

小结

InheritedWidget是了解其它状态管理框架的基础,但它并不是解决所有状态管理问题的唯一方法。在实际开发中,根据具体情况选择合适的状态管理工具和模式是至关重要的。除了InheritedWidget之外,还有许多其他状态管理解决方案,如Provider、Bloc等,每种解决方案都有其适用的场景和优势。好了今天就分享到这里,感谢您的阅读!

本文原文来自CSDN

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号