Flutter didUpdateWidget 和 didChangeDependencies

didUpdateWidget

这个方法用于更新 widget 的变量,如果想要在 widget 的变量发生变化后 ui 能得到更新,需要重载这个函数,并更新变量。

class TestName extends StatefulWidget {
final String name;
const TestName({super.key, required this.name});

@override
State<TestName> createState() => TestNameState();
}

class TestNameState extends State<TestName> {
String? userName ;

@override
void initState() {
super.initState();

userName = widget.name;
}

@override
void didUpdateWidget(covariant TestName oldWidget) {
super.didUpdateWidget(oldWidget);

if (widget.name != oldWidget.name) {
userName = widget.name;
}
}

@override
Widget build(BuildContext context) {
return Text(userName!);
}
}

上述因为在 initState 中 userName = widget.name; ,如果没有在 didUpdateWidget 进行更新,会导致 userName 不更新,需要通过其他途径,比如通过 ProviderNotifier

如果TestNameState没有定义依赖于TestName的变量,那就不需要重载didUpdateWidget

didChangeDependenciesdidUpdateWidget

didChangeDependencies 响应的是上下文依赖变化(如主题、媒体查询、Provider状态)
didUpdateWidget 响应的是 widget 自身配置变化(如父 widget 传入的属性改变)

使用场景示例:如果你的 widget 使用 Provider 获取数据,数据变化会触发 didChangeDependencies;而如果父 widget 传入的参数发生变化,则会触发 didUpdateWidget

什么是“上下文依赖”和“自身配置”

“上下文依赖”和”自身配置”是描述 Flutter Widget 获取数据和设置参数的两种不同方式:

自身配置(Widget Configuration)

  • 指通过构造函数直接传入 Widget 的参数

上下文依赖(Context Dependencies)

  • Widget 通过 BuildContextWidget 树上层获取的数据
  • 典型例子是通过 InheritedWidget 传递的数据,如:
    • Theme.of(context) - 获取应用主题
    • MediaQuery.of(context) - 获取设备信息
    • Provider.of<T>(context) - 获取状态管理数据
  • 这些数据不是直接作为参数传入 Widget,而是通过 context 间接获取
  • 当这些上下文数据发生变化时,会触发 didChangeDependencies

scheduleMicrotask 和 Future.microtask

以下内容来自 AI

后者是通过前者实现的。当你在 widget 的生命周期方法(如 initStatedidChangeDependenciesdidUpdateWidget)中调用 scheduleMicrotask 时,这个微任务会在当前帧的 build 方法执行完成后执行。

因此,如果要在一部函数中调用 setState,最好放在微任务中。

WidgetsBinding.instance.addPostFrameCallback 和 Future.microtask 的区别

以下内容来自 AI

特性 WidgetsBinding.instance.addPostFrameCallback Future.microtask
执行时机 当前帧绘制完成后 当前任务完成后,下一个事件循环开始前
优先级 较低 较高
用途侧重 UI 可见后的操作(例如,动画启动、首次显示等) 避免构建错误、尽快执行的短任务、状态更新的延迟执行
触发新帧 调用 setState 会触发新的帧调用 setState 会标记为需要重新构建,在下一个帧发生

在处理 didUpdateWidget 中异步操作完成后的 setState 调用时,Future.microtask 通常是更好的选择,因为它能确保状态更新在当前构建周期结束后尽快发生,从而避免错误。而 addPostFrameCallback 会将更新推迟到下一个渲染帧,这可能会导致轻微的视觉延迟。