西红柿带你看 InheritedElement 更新!
2023-11-26 20:46:24
深度剖析 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');
}
}