跳至主要內容

OverlayEntries 和路由的重建優化

摘要

#

此優化改善了路由轉場的效能,但可能會發現應用程式中遺漏的 setState 呼叫。

背景

#

在進行此變更之前,當在其上方新增或移除新的不透明項目時,OverlayEntry 會重建。這些重建是不必要的,因為它們不是由受影響的 OverlayEntry 的狀態變更所觸發。此重大變更優化了我們處理 OverlayEntry 新增和移除的方式,並移除了不必要的重建以改善效能。

由於 Navigator 內部將每個 Route 放入一個 OverlayEntry 中,此變更也適用於 Route 的轉場效果:如果一個不透明的 Route 被推到另一個 Route 的上方,或從上方移除,則不透明 Route 下方的 Route 不會再不必要地重建。

變更說明

#

在大多數情況下,此變更不需要您修改任何程式碼。但是,如果您的應用程式錯誤地依賴於隱式的重建,您可能會遇到問題,這些問題可以透過將任何狀態變更包裝在 setState 呼叫中來解決。

此外,此變更稍微修改了 widget 樹的形狀:在此變更之前,OverlayEntry 被包裹在一個 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