跳到主內容

區分臨時狀態 (Ephemeral state) 和應用狀態 (App state)

如何區分臨時狀態和應用狀態。

本文介紹了什麼是應用狀態、臨時狀態,以及如何在 Flutter 應用中管理它們。

從最廣泛的意義上講,應用的狀態是指應用執行時記憶體中存在的一切。這包括應用的資源、Flutter 框架儲存的有關 UI 的所有變數、動畫狀態、紋理、字型等。雖然這種最廣泛的狀態定義是有效的,但對於構建應用架構來說,它並不是很有用。

首先,有些狀態你甚至不需要管理(比如紋理),框架會為你處理這些。因此,一個更有用的狀態定義是:“任何你需要在任何時刻重新構建 UI 時所需的資料”。其次,你自己管理的狀態可以分為兩種概念型別:臨時狀態和應用狀態。

臨時狀態

#

臨時狀態(有時稱為 UI 狀態區域性狀態)是指你可以整齊地包含在單個 widget 中的狀態。

這是一個有意為之的模糊定義,因此這裡列舉幾個示例。

  • PageView 中的當前頁面
  • 複雜動畫的當前進度
  • BottomNavigationBar 中當前選中的標籤頁

widget 樹的其他部分很少需要訪問這種狀態。無需對其進行序列化,它也不會以複雜的方式改變。

換句話說,無需對此類狀態使用狀態管理技術(ScopedModel、Redux 等)。你只需要一個 StatefulWidget 即可。

在下方,你可以看到底部導航欄中當前選中的項是如何儲存在 _MyHomepageState 類的 _index 欄位中的。在這個例子中,_index 就是臨時狀態。

dart
class MyHomepage extends StatefulWidget {
  const MyHomepage({super.key});

  @override
  State<MyHomepage> createState() => _MyHomepageState();
}

class _MyHomepageState extends State<MyHomepage> {
  int _index = 0;

  @override
  Widget build(BuildContext context) {
    return BottomNavigationBar(
      currentIndex: _index,
      onTap: (newIndex) {
        setState(() {
          _index = newIndex;
        });
      },
      // ... items ...
    );
  }
}

在這裡,使用 setState() 和 StatefulWidget 的 State 類中的欄位是非常自然的。應用的其餘部分不需要訪問 _index。該變數僅在 MyHomepage widget 內部發生變化。而且,如果使用者關閉並重新啟動應用,你也不會在意 _index 是否重置為零。

應用狀態

#

非臨時狀態,即你希望在應用的多處共享,並且希望在使用者會話之間保留的狀態,我們稱之為應用狀態(有時也稱為共享狀態)。

應用狀態示例

  • 使用者偏好設定
  • 登入資訊
  • 社交網路應用中的通知
  • 電商應用中的購物車
  • 新聞應用中文章的已讀/未讀狀態

對於管理應用狀態,你需要研究各種可選方案。你的選擇取決於應用的複雜程度和性質、團隊的既往經驗以及許多其他方面。請繼續閱讀。

沒有明確的界限

#

需要明確的是,你完全可以使用 StatesetState() 來管理應用中的所有狀態。事實上,Flutter 團隊在許多簡單的應用示例(包括每次執行 flutter create 時生成的啟動應用)中就是這樣做的。

反之亦然。例如,你可能會認為——在特定應用的上下文中——底部導航欄中選中的標籤頁並非臨時狀態。你可能需要從類外部更改它,或者在會話之間保留它等。在這種情況下,_index 變數就屬於應用狀態。

沒有明確的、通用的規則來區分某個變數到底是臨時狀態還是應用狀態。有時,你必須將一種狀態重構為另一種。例如,你從某種明顯的臨時狀態開始,但隨著應用功能的增長,它可能需要被移動到應用狀態中。

因此,請以審慎的態度對待下方的圖表

A flow chart. Start with 'Data'. 'Who needs it?'. Three options: 'Most widgets', 'Some widgets' and 'Single widget'. The first two options both lead to 'App state'. The 'Single widget' option leads to 'Ephemeral state'.

當被問及 React 的 setState 與 Redux 的 store 之間的區別時,Redux 的作者 Dan Abramov 回答道:

“經驗法則是:怎麼不彆扭就怎麼做。”

總之,任何 Flutter 應用中都有兩種概念上的狀態。臨時狀態可以使用 StatesetState() 實現,通常侷限於單個 widget。其餘的則是你的應用狀態。這兩種型別在任何 Flutter 應用中都有其一席之地,兩者之間的劃分取決於你自己的偏好和應用的複雜程度。