Shared state management - simple use of InheritedWidget
InheritedWidget
It is a very important functional component in Flutter, which provides a way to share data from top to bottom in the widget tree,
InheritedWidge
The functions in t and React
in context
are similar, and can realize the transfer of cross-component data. InheritedWidget
The direction of data transfer in the widget tree is from top to bottom.
First look at InheritedWidget
the source code,
- In the construction of InheritedWidget, a child needs to be passed in, and this child is a sub-widget that needs to use shared data
- updateShouldNotify This abstract method needs to be implemented by subclasses
abstract class InheritedWidget extends ProxyWidget {
/// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions.
const InheritedWidget({
super.key, required super.child });
InheritedElement createElement() => InheritedElement(this);
/// Whether the framework should notify widgets that inherit from this widget.
///
/// When this widget is rebuilt, sometimes we need to rebuild the widgets that
/// inherit from this widget but sometimes we do not. For example, if the data
/// held by this widget is the same as the data held by `oldWidget`, then we
/// do not need to rebuild the widgets that inherited the data held by
/// `oldWidget`.
///
/// The framework distinguishes these cases by calling this function with the
/// widget that previously occupied this location in the tree as an argument.
/// The given widget is guaranteed to have the same [runtimeType] as this
/// object.
bool updateShouldNotify(covariant InheritedWidget oldWidget);
}
To define a shared data for the "counter" sample application InheritedWidget
, it needs to inherit from InheritedWidget
, as follows:
class CounterWidget extends InheritedWidget {
// 1.需要共享的数据
final int counter;
// 2.定义构造方法 传入最新的 counter值
CounterWidget({
this.counter, Widget child}): super(child: child);
// 3.获取组件最近的当前InheritedWidget
static CounterWidget of(BuildContext context) {
// 沿着Element树, 去找到最近的CounterElement, 从Element中取出Widget对象
return context.dependOnInheritedWidgetOfExactType();
}
// 4.绝对要不要回调State中的didChangeDependencies
// 如果返回true: 执行依赖当期的InheritedWidget的State中的 didChangeDependencies
bool updateShouldNotify(CounterWidget oldWidget) {
return oldWidget.counter != counter;
}
}
-
The data to be shared is a counter of type int
-
Assign a value to the counter in the construction, and the child is the widget that needs to use the data
-
Defines an of method, which starts to find the ancestors through the context
CounterWidget
-
updateShouldNotify
The method is to compare the old and newCounterWidget
, and whether to update the Widget that depends on itIf it returns true: Execution depends on the state of the current InheritedWidget
didChangeDependencies
To use in the example CounterWidget
, define the ShowDataWidget subcomponent to use shared data:
class _HomePageState extends State<HomePage> {
int _counter = 100;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("InheritedWidget"),
),
body: CounterWidget(//使用CounterWidget 将需要使用数据widget包裹
counter: _counter,
child: Center(
child: ShowDataWidget(),//在ShowDataWidget 中去使用共享的数据
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
setState(() {
_counter++;
});
},
),
);
}
}
class ShowDataWidget extends StatefulWidget {
_ShowDataWidgetState createState() => _ShowDataWidgetState();
}
class _ShowDataWidgetState extends State<ShowDataWidget> {
void didChangeDependencies() {
super.didChangeDependencies();
print("执行了ShowDataWidget中的didChangeDependencies");
}
Widget build(BuildContext context) {
int counter = CounterWidget.of(context).counter;
return Card(
color: Colors.red,
child: Text("当前计数: $counter", style: TextStyle(fontSize: 30),),CounterWidget
);
}
}
We can see that:
-
After pressing the floatingActionButton here, call setState to re-call the build method of _HomePageState, and then re-create and
CounterWidget
pass in the latest counter value. -
ShowDataWidget
Get the instance by callingCounterWidget
the **of** method in ,CounterWidget
and get the shared data counterint counter = CounterWidget.of(context).counter;
-
We see that the method
_ShowDataWidgetState
indidChangeDependencies
is calledThe method will be called
didChangeDependencies
by the Flutter framework when the "dependency" changes. And this "dependency" refers to whether the child widget uses the data of the InheritedWidget in the parent widget! If it is used, it means that the sub-widget has dependencies; if it is not used, it means it has no dependencies. This mechanism allows subcomponents to update themselves when the dependent InheritedWidget changes! For example, when the theme, locale (language), etc. change, the didChangeDependencies method of the sub-widget that depends on it will be called.2022-11-09 13:11:06.175 14203-14233/com.example.learn_flutter I/flutter: 执行了_ShowData01State中的didChangeDependencies 2022-11-09 13:11:07.383 14203-14233/com.example.learn_flutter I/flutter: 执行了_ShowData01State中的didChangeDependencies 2022-11-09 13:11:08.248 14203-14233/com.example.learn_flutter I/flutter: 执行了_ShowData01State中的didChangeDependencies 2022-11-09 13:11:08.999 14203-14233/com.example.learn_flutter I/flutter: 执行了_ShowData01State中的didChangeDependencies
The effect is as follows: