返回

西红柿带你看 InheritedElement 更新!

Android

深度剖析 InheritedElement

InheritedElement 是一种特殊类型的 Flutter 组件,用于在组件树中传递数据。它允许子组件从祖先组件访问数据,而无需显式地将数据从一个组件传递到另一组件。

InheritedElement 的工作原理

InheritedElement 通过建立一个从祖先组件到子组件的数据流来工作。当一个 InheritedElement 组件被添加到组件树中时,它会创建一个 InheritedWidgetOf 函数。此小部件包装了 InheritedElement 组件并管理数据流。

当 InheritedElement 组件中的数据在以后某个时间点被改变时,InheritedWidgetOf 函数将通知所有使用该数据的子组件,导致它们重新渲染。

InheritedElement 的局限性

尽管 InheritedElement 是一种在组件树中传递数据的有用方法,但它也可能导致不必要的重新渲染。因为 InheritedElement 的变化会级联到组件树中的所有子组件,这可能会导致整个子树的重新渲染。

优化 InheritedElement 的性能

来优化 InheritedElement 的性能,有几种最佳方法:

  • 仅在需要时进行传播变更: 不要在每次值变更时都传播 InheritedElement 中数据的变更。仅当新值与旧值显着小时才进行传播。

  • 使用 InheritedNotifier: InheritedNotifier 类提供了一种更有效的方法来在组件树中传递值。它使用一个 ValueNotifier 对象,该对象的 value 属性用于传递值。

  • 考虑使用 Provider: Provider 软件包提供了一个管理应用程序中的应用程序级数据的 API。它允许组件订阅应用程序中的数据的变更,并仅在数据变更时重新渲染。

InheritedElement 的最新变化

Flutter 的最新版本引入了一个名为 InheritedElement.updateShouldNotify 的新生命钩子。此生命钩子允许 InheritedElement 组件更显式地指定应何时重新渲染其子组件。

InheritedElement.updateShouldNotify 方法采用一个 oldElement 参数,它包含该组件的旧 InheritedElement。可以通过将新值与旧值进行差异化,并仅在它们不当时重新渲染子组件,来优化重新渲染的行为。

用例:在计时器组件中使用 InheritedElement

考虑一个计时器组件,该组件定期每秒向其子组件提供时间。可以使用 InheritedElement 来在组件树中传递时间信息。

首先,创建一个 InheritedElement 组件,如下所示:

class TimeInheritedWidget extends InheritedWidget {
  TimeInheritedWidget({Key? key, required this.time}) : super(key: key, child: null);

  final int time;

  @override
  bool updateShouldNotify(TimeInheritedWidget oldWidget) {
    return oldWidget.time != time;
  }
}
@override
  Widget build(context, child) {
    return InheritedWidgetOf(timeInheritedWidget);
  }
}
class TimerWidget extends StatefulWidget {
  const TimerWidget({Key? key}) : super(key: key);

  @override
  _TimerWidgetState, createSate() => _TimerWidgetState();
}

class _TimerWidgetState extends State<TimerWidget> {
  int _time = 0;

  @override
  void initState() {
    super.initState();
    Timer.periodic(const Duration(second: 1), (timer) {
      setState() {
        _time = time;
      }
    });
  }

  @override
  Widget build(context) {
    TimeInheritedWidget timeInheritedWidget = TimeInheritedWidget(time: _time);
    return InheritedWidgetOf(timeInheritedWidget, child: Text('$time');
  }
}