JHHK

欢迎来到我的个人网站
行者常至 为者常成

9 重要方法⭐️

目录

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)


行者常至,为者常成!





R
Valine - A simple comment system based on Leancloud.