目录
didUpdateWidget:什么时候会被调用?
一、触发的完整条件
1、父 widget 触发 rebuild
2、Flutter 决定「复用旧 Element」
3、新 widget != old widget(配置发生变化)
少一个都不会进 didUpdateWidget
如果widget是 const 修饰,不会进入该方法,也不会走state的build的方法
二、典型使用场景
外部参数变化,需要同步内部状态
class Counter extends StatefulWidget {
final int initial;
const Counter({super.key, required this.initial});
@override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
late int value;
// initState 只跑一次
@override
void initState() {
super.initState();
value = widget.initial;
}
@override
void didUpdateWidget(covariant Counter oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.initial != widget.initial) {
value = widget.initial; // 同步新配置
}
}
// didUpdateWidget 负责“配置更新”
@override
Widget build(BuildContext context) {
return Text('$value');
}
}
三、常见误区(重点)
外部刷新时,先调用didUpdateWidget在调用build。
内部的 setState 不会触发 didUpdateWidget。
build 不会调用 didUpdateWidget。
StatelessWidget 不需要刷新,父类rebuild时,它会直接创建新的。没有didUpdateWidget方法。
update相关方法
假设都是普通 Widget(无 key)
A
└─ B
└─ C
Element 树(第一次 build 后)
ElementA(widget: A1)
└─ ElementB(widget: B1)
└─ ElementC(widget: C1)
1️⃣ 父级 setState
A2 // 新的 Widget 实例
Flutter 做的是:
ElementA.update(A2)
于是:
ElementA.widget = A2
2️⃣ ElementA 调用 performRebuild()
接下来:
ElementA.performRebuild()
内部做一件事:
Widget newChild = A2.build(context);
假设 build 结果是:
B2
3️⃣ 关键一步:updateChild(A → B)
ElementA.updateChild(
oldChild: ElementB,
newWidget: B2,
)
Flutter判断:
canUpdate(B1, B2)
= runtimeType 相同
= key 相同(null)
✅ 可以复用,于是执行:
ElementB.update(B2)
➡️ 关键动作发生了
ElementB.widget = B2
📌 重点:
B 的 Element 没换,只是 Widget 引用从 B1 换成了 B2
didChangeDependencies
一、调用时机
1、State 第一次插入 Element 树时
initState
↓
didChangeDependencies ✅
↓
build
2、依赖的 InheritedWidget 发生变化时
系统字体缩放改变
屏幕旋转(MediaQuery 变化)
Theme 切换(深色 / 浅色)
Provider 中的数据更新
二、典型示例
class MyWidget extends StatefulWidget {
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
late Color textColor;
@override
void didChangeDependencies() {
super.didChangeDependencies();
// 依赖 Theme
textColor = Theme.of(context).textTheme.bodyLarge!.color!;
print('didChangeDependencies');
}
@override
Widget build(BuildContext context) {
return Text(
'Hello',
style: TextStyle(color: textColor),
);
}
}
MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
)
三、结合 Element 更新机制
当在 build 里写:
Theme.of(context)
底层发生的是:
Element.dependOnInheritedElement(...)
这意味着:当前 Element 登记 了一个依赖
InheritedWidget 更新时:
不会重建整棵树,不会销毁 MyWidget
只通知“依赖它的 Element”,然后回调 👉 didChangeDependencies
四、什么时候“应该”用 didChangeDependencies?
✅ 适合放在这里的逻辑
依赖 Theme / MediaQuery / Locale / Provider
需要在依赖变化时重新计算一次的值
不想在 build 里反复算
❌ 不适合
父 Widget 参数变化(用 didUpdateWidget)
一次性初始化(用 initState)
UI 渲染(用 build)
行者常至,为者常成!