OverlayEntries 和 Routes 进行了重建优化
概述
本次优化提高了路由切换时的性能,但可能会揭露出你的应用中没有显式调用 setState
的问题。
上下文
在此更改之前,当一个新的不透明 OverlayEntry
(记作 A)被添加到另一个 OverlayEntry
(记作 B)上,或者 A 从 B 上移除时,B 将会重新构建。这些重建是不必要的,因为它们不是由 OverlayEntry
内部状态发生的改变而触发的。这个破坏性的改动优化了我们对 OverlayEntry
进行添加和移除的场景,移除了不必要的重建以提高性能。
由于 Navigator
在内部会把每一个 Route
嵌套在 OverlayEntry
中,因此这个改动同样作用于 Route
的变换:如果一个不透明的 Route
被添加到栈顶,或是从另一个 Route
的上层被移除时,位于不透明的 Route
下面的 Route
将不再进行不必要的重建。
更改描述
在大多数情况下,本次优化不需要你对代码进行任何更改。然而,如果你的应用错误地依赖了隐式重建,你可能会发现问题,这可以通过调用 setState
进行状态的变更来解决。
此外,这一更改略微调整了 widget 树的层级结构:在此更改之前,OverlayEntry
集合嵌套在 Stack
中。更改后,Stack
将从 widget
树结构中移除。
迁移指南
如果你在升级到包含此次更改的 Flutter 版本后遇到了问题,请检查你的代码是否遗漏了 setState
的调用。在下面的例子中,Navigator.pushNamed
方法异步执行完后隐式地修改了 Text
所展示的字符串 buttonLabel
,它应该在显式的 setState
中调用。
迁移前代码:
class FooState extends State<Foo> {
String buttonLabel = 'Click Me';
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () async {
// Illegal state modification that should be wrapped in setState.
buttonLabel = await Navigator.pushNamed(context, '/bar');
},
child: Text(buttonLabel),
);
}
}
迁移后代码:
class FooState extends State<Foo> {
String buttonLabel = 'Click Me';
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () async {
final newLabel = await Navigator.pushNamed(context, '/bar');
setState(() {
buttonLabel = newLabel;
});
},
child: Text(buttonLabel),
);
}
}
时间轴
发布于版本:1.16.3
发布于稳定版本:1.17
参考文献
API 文档:
相关 issues:
相关 PR: