概述

#

这项优化提升了路由转换的性能,但可能会暴露出您的应用中缺失的 setState 调用。

背景

#

在此更改之前,当一个新的不透明 OverlayEntry 添加到其上方或从其上方移除时,OverlayEntry 会重建。这些重建是不必要的,因为它们并非由受影响 OverlayEntry 的状态变化触发。这项破坏性更改优化了我们处理 OverlayEntry 的添加和移除方式,并消除了不必要的重建以提升性能。

由于 Navigator 内部将每个 Route 放入一个 OverlayEntry 中,因此此更改也适用于 Route 转换:如果一个不透明的 Route 被推到另一个 Route 的上方或从其上方移除,不透明 Route 下方的 Route 将不再进行不必要的重建。

变更说明

#

在大多数情况下,此更改不需要对您的代码进行任何修改。但是,如果您的应用错误地依赖于隐式重建,您可能会遇到问题,可以通过将任何状态更改封装在 setState 调用中来解决。

此外,此更改略微修改了 widget 树的结构:在此更改之前,OverlayEntrys 被封装在一个 Stack widget 中。现在,显式的 Stack widget 已从 widget 层次结构中移除。

迁移指南

#

如果您在升级到包含此更改的 Flutter 版本后遇到问题,请检查您的代码中是否有缺失的 setState 调用。在下面的示例中,将 Navigator.pushNamed 的返回值赋值给 buttonLabel 隐式修改了状态,这应该被封装在一个显式的 setState 调用中。

迁移前的代码

dart
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),
    );
  }
}

迁移后的代码

dart
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 文档

相关问题

相关 PR