乐趣区

关于flutter:记InheritedWidget使用思考

记 InheritedWidget 应用思考

InheritedWidget 是我的项目中必不可少的组件,用户数据共享。陈词滥调的 Provider 框架也是基于 InheritedWidget 实现的

简介

InheritedWidget组件是功能性组局,实现了由上向下共享数据的性能。即子组件通过 BuildContext.dependOnInheritedWidgetOfExactType 办法从父组件获取数据。

值得提一下,这种由上向下提供书共享数据的形式和 Notification 传递方向正好相同。两者相同点是:都是由子组件发动的。InheritedWidget是又子组件通过 content 向树上方查找数据,Notification是由子组件向上发动告诉。

特点

  1. 子组件通过 [BuildContext.dependOnInheritedWidgetOfExactType] 办法查找对应最近的 InheritedWidget 并获取数据。
  2. InheritedWidget依据习惯或者协定,提供 of 静态方法,便于子组件获取数据。该办法并非肯定返回该继承的 widget,也能够返回其余数据。
  3. 调用 of 办法的组件,必须要在 InheritedWidget 内。如果在同一个 widget 中应用,能够通过 Builder 将须要应用的组件包裹起来。

作用

在应用中咱们发现,InheritedWidget作用是父组件提供数据,子组件能够由下往上查找对应的共享数据,这个是它直观的作用。

罕用的谬误更新数据形式

setState:咱们发现网上的有很多文章在介绍 InheritedWidget 的应用,并更新数据。然而这个只是体现了该组件的作用。绝大多数是在 InheritedWidget 组件中通过 final 申明共享数据。而后在父组件中通过 setState 强制刷新父组件,同时也刷新了 InheritedWidget 组件,当然其多层子组件都会跟着一起rebuild,造成了很大的非必要耗费。

如何去优化?

InheritedWidget提供了数据的共享,防止了数据由上到下层层申明传递。咱们应用数据的中央也很明确。接下来要做的是,数据刷新后,让指定组件去更新 。这个时候咱们就想到了ValueNotifierInheritedWidget 在共享数据的时候通过 ValueNotifier 包裹,子组件通过 of 办法获取的数据类型也是 ValueNotifier,在应用的中央通过ValueListenableBuilder 实现

进一步思考

在【老孟 Flutter】源码剖析系列之 InheritedWidget 一文中提到了,批改 of 办法:

  • dependOnInheritedWidgetOfExactType
  • getElementForInheritedWidgetOfExactType<T>().widget

    两者的区别:调用 dependOnInheritedWidgetOfExactType() 和 getElementForInheritedWidgetOfExactType()的区别就是前者会注册依赖关系,而后者不会 ,所以在调用 dependOnInheritedWidgetOfExactType() 时,InheritedWidget 和依赖它的子孙组件关系便实现了注册,之后当 InheritedWidget 发生变化时,就会更新依赖它的子孙组件,也就是会调这些子孙组件的 didChangeDependencies()办法和 build()办法。而当调用的是 getElementForInheritedWidgetOfExactType()时,因为没有注册依赖关系,所以之后当 InheritedWidget 发生变化时,就不会更新相应的子孙 Widget。

    @override
    T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object? aspect}) {assert(_debugCheckStateIsActiveForAncestorLookup());
    final InheritedElement? ancestor =
        _inheritedWidgets == null ? null : _inheritedWidgets![T];
    // 多出局部
    if (ancestor != null) {assert(ancestor is InheritedElement);
      return dependOnInheritedElement(ancestor, aspect: aspect) as T;
    }
    _hadUnsatisfiedDependencies = true;
    return null;
    }
    
    @override
    InheritedElement?
      getElementForInheritedWidgetOfExactType<T extends InheritedWidget>() {assert(_debugCheckStateIsActiveForAncestorLookup());
    final InheritedElement? ancestor =
        _inheritedWidgets == null ? null : _inheritedWidgets![T];
    return ancestor;
    }

很显著批改为getElementForInheritedWidgetOfExactType<T>().widget,就会少一个非必要注册,也算是坏事。

进一步思考产生疑难

既然通过了 ValueNotifierInheritedWidget联合,咱们通过批改 ValueNotifier 的 value 来扭转页面时,InheritedWidget组件没有从新构建并不会触发 updateShouldNotify,也就是在应用数据的子组件中didChangeDependencies 办法也不会因为 value 的扭转而调用。
所以 of 办法具体用什么去实现,取决于具体业务设计。

文中的图片均借用于【老孟 Flutter】源码剖析系列之 InheritedWidget

退出移动版