【发布时间】:2019-02-12 01:51:19
【问题描述】:
阅读文档here 和State 生命周期here 后,我仍然不确定didChangeDependencies 的工作原理。
据我了解,它将在initState 和InheritedWidget 发生任何更改之后触发,但这些更改是什么?我认为了解什么更改触发didChangeDependencies 很重要,这样我们才能了解何时以及如何正确使用它。
【问题讨论】:
标签: flutter
阅读文档here 和State 生命周期here 后,我仍然不确定didChangeDependencies 的工作原理。
据我了解,它将在initState 和InheritedWidget 发生任何更改之后触发,但这些更改是什么?我认为了解什么更改触发didChangeDependencies 很重要,这样我们才能了解何时以及如何正确使用它。
【问题讨论】:
标签: flutter
didChangeDependencies() 在此 [State] 对象的依赖项发生更改时调用。
那么,究竟它是如何被调用的? 根据上面的定义,看起来它会在状态改变后被调用,但我们是如何知道状态改变的呢?
例子:
下面的示例使用 Provider 状态管理机制从父窗口小部件更新子窗口小部件。 Provider 有一个名为 updateShouldNotify 的属性,它决定是否更改状态。如果它返回 true,那么只会在 ChildWidget 类中调用 didChangeDependencies。
updateShouldNotify 默认在内部返回 true,因为它知道状态已更改。
为什么我们需要 updateShouldNotify?
这是必需的,因为如果有人想在特定条件下更新状态。例如:如果 UI 需要仅显示偶数值,那么我们可以添加一个条件,如
updateShouldNotify: (oldValue, newValue) => newValue % 2 == 0,
代码片段:
class ParentWidget extends StatefulWidget {
ParentWidget({Key key, this.title}) : super(key: key);
final String title;
@override
_ParentWidgetState createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Life Cycle'),
),
body: Provider.value(
value: _counter,
updateShouldNotify: (oldValue, newValue) => true,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Press Fab button to increase counter:',
),
ChildWidget()
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class ChildWidget extends StatefulWidget {
@override
_ChildWidgetState createState() => _ChildWidgetState();
}
class _ChildWidgetState extends State<ChildWidget> {
int _counter = 0;
@override
void initState() {
print('initState(), counter = $_counter');
super.initState();
}
@override
void didChangeDependencies() {
_counter = Provider.of<int>(context);
print('didChangeDependencies(), counter = $_counter');
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
print('build(), counter = $_counter');
return Text(
'$_counter',
);
}
}
输出日志:
I/flutter ( 3779): didChangeDependencies(), counter = 1
I/flutter ( 3779): build(), counter = 1
更多信息:
https://medium.com/@jitsm555/differentiate-between-didchangedependencies-and-initstate-f98a8ae43164
【讨论】:
_ChildWidgetState 的build 方法没有“引用”任何底层InheritedWidget,是吗?那么,如果对它的唯一“引用”来自didChangeDependencies 本身,Flutter 怎么知道提供者是一个依赖项?
作为 Widget 的创建者,您通过使用 of 或 maybeOf 等设置它的依赖项(InheritedWidget),因此您应该了解他们何时调用 updateShouldNotify(或者他们是依赖项调用它)。这很复杂:
您通常不必在State 中重写此方法,因为无论如何当依赖项发生更改时,您的小部件都会重新构建。如果您想做昂贵的工作,例如发出网络请求,那么您将避免在正常构建中发出该网络请求,而是将这项昂贵的工作放在didChangeDependencies 中。这允许您仅在依赖项更改时进行这些昂贵的操作。 Tbh,如果您将应用程序的逻辑正确地构建到服务中,那么我很难想到如果InheritedWidget 发生更改,那么您只想进行昂贵的操作。于是我查看了 Flutter 框架的内部结构......
didChangeDependencies 覆盖示例:Image 小部件(cmets 是我的评论,tbh load 可能不是我使用的正确词,但 resolve 恕我直言也好不到哪里去) @override
void didChangeDependencies() {
_updateInvertColors(); // Checks if the image should inverted or not.
_resolveImage(); // Reloads the image if necessary?
if (TickerMode.of(context)) // This method returns a bool: Whether tickers in the given subtree should be enabled or disabled.
_listenToStream(); // Keep loading the image
else
_stopListeningToStream(keepStreamAlive: true); // Be efficient and not read from the stream if not needed. (ticker is false)
super.didChangeDependencies();
}
didChangeDependencies?又名。 Image 的依赖项是什么(都是InheritedWidgets)?它使用both of and maybeOf注册InheritedWidget依赖,包括MediaQuery、Directionality、DefaultAssetBundle、TickerMode、Localizations。因此,当这些依赖项更改/更新时,Image 的didChangeDependencies 将被调用。您使用InheritedWidgetType.of(context) 使一个小部件依赖在InheritedWidget 的子类型上,该子类型在内部调用context.dependOnInheritedWidgetOfExactType<InheritedWidgetType>();。所以小部件依赖于InheritedWidget。比如Theme.of(BuildContext context)可以看到here。
来自 Flutter Framework 的 cmets 中关于 dependOnInheritedWidgetOfExactType 的文档:
获取给定类型
T最近的widget,它必须是 具体 [InheritedWidget] 子类的类型,并注册它 使用该 widget 构建上下文,以便当该 widget 更改(或 引入了该类型的新 widget,或者 widget 消失), 这个构建上下文被重建,以便它可以从 那个小部件。一旦 widget 通过调用注册对特定类型的依赖项 这个方法,它会被重建,并且[State.didChangeDependencies] 每当与该小部件相关的更改发生时都会调用,直到 下次移动小部件或其祖先之一时(对于 例如,因为添加或删除了祖先)。
有more docs, which are really interesting, have a read。
Jitesh's answer 目前是错误的。依赖不是Widget的状态,它们只与InheritedWidget相关。
【讨论】:
当 Flutter 调用 updateShouldNotify() 并返回 true 时,之前在 build() 中请求继承的小部件的小部件会通过被调用的 didChangeDependencies 通知。
updateShouldNotify 应该返回 true,如果它的状态自上次调用以来发生了变化。
【讨论】: