概述

#

此最佳化提高了路由過渡的效能,但可能會暴露您應用中缺失的 setState 呼叫。

背景

#

在此更改之前,當一個新的不透明條目新增到 OverlayEntry 之上或從其上方移除時,該 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