Flutter MobX 響應式原理與實戰詳解

📚 Flutter 狀態管理系列文章目錄
  1. Flutter 狀態管理(setState、InheritedWidget、 Provider 、Riverpod、 BLoC / Cubit、 GetX 、MobX 、Redux)

  2. setState() 使用詳解:原理及注意事項

  3. InheritedWidget 組件使用及原理

  4. Flutter 中 Provider 的使用、注意事項與原理解析(含代碼實戰)

  5. GetX 用法詳細解析以及注意事項

  6. Flutter BLoC 使用詳細解析

  7. Flutter MobX 響應式原理與實戰詳解

  8. Flutter Riverpod 使用詳細解析

  9. Riverpod原理解析(實現一個自己的Riverpod

? 起點:為什么要了解 MobX?

作為一個剛開始接觸 Flutter 狀態管理的開發者,我最初接觸到的是 setStateProvider 等方式。當我看到有人說 MobX 是“最像魔法的狀態管理庫”時,我開始好奇:為什么它能不寫 setState 就自動刷新 UI?

帶著這樣的疑問,我開啟了對 MobX 的深入探索。這篇文章就是我把所有探索過程系統整理后的總結,希望對你也有幫助。


🛠 一、MobX 的安裝與基本使用

MobX 的核心有三大類:

概念說明
Observable可觀察狀態,類似變量。變化時自動觸發 UI 更新
Action改變狀態的行為,所有狀態變更建議通過 action
Reaction監聽變化后做副作用,比如打印日志、導航等

1. 添加依賴

pubspec.yaml 中:

dependencies:flutter:sdk: fluttermobx: ^2.2.0flutter_mobx: ^2.0.6dev_dependencies:build_runner: ^2.4.6mobx_codegen: ^2.4.0

2.創建一個 MobX Store(狀態容器)

counter_store.dart

import 'package:mobx/mobx.dart';part 'counter_store.g.dart'; // 自動生成的文件class CounterStore = _CounterStore with _$CounterStore;abstract class _CounterStore with Store {int count = 0;void increment() {count++;}
}

生成代碼命令:

flutter pub run build_runner build
# 或者自動監聽:
flutter pub run build_runner watch

3. 使用 Observer 監聽狀態

import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'counter_store.dart';class CounterPage extends StatelessWidget {final CounterStore counter = CounterStore();Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text("MobX Counter")),body: Center(child: Observer(builder: (_) => Text('${counter.count}',style: TextStyle(fontSize: 40),),),),floatingActionButton: FloatingActionButton(onPressed: counter.increment,child: Icon(Icons.add),),);}
}

📚 二、MobX 核心注解說明

注解作用示例
@observable可監聽變量@observable int count = 0;
@action狀態改變函數@action void increment() => count++;
@computed派生狀態String get fullName => "$firstName $lastName";

🧩 三、不同類型的 Observer 使用方式

類型使用場景是否支持 child是否自動跟蹤依賴
Observer通用 UI 刷新??
Observer.builder自定義構建器??
ObserverWidget(自定義)可封裝為組件??
Observer + child:子組件不依賴狀態,可優化性能??

1?? 最常用的 Observer

適用于所有直接在 build() 方法中監聽 observable 狀態的場景。

? 示例:
Observer(builder: (_) => Text('${counter.count}',style: TextStyle(fontSize: 32),),
)

每當 counter.count 更新時,Text 會自動重建。


2?? Observer + child 優化重建

用于優化性能:當 UI 中部分元素是靜態的,可以通過 child 參數避免重建。

? 示例:
Observer(child: Icon(Icons.favorite), // 不會因為狀態變化而重建builder: (_, child) => Row(mainAxisAlignment: MainAxisAlignment.center,children: [child!,SizedBox(width: 8),Text('${counter.count}'),],),
)

? Icon 是靜態內容,MobX 不會重復創建,節省性能。


3?? 封裝成組件:自定義 ObserverWidget

當你想將 Observer 封裝成復用組件時,可創建一個繼承自 StatelessWidgetObserver 控件。

? 示例:
class CountText extends StatelessWidget {final CounterStore store;const CountText({required this.store});Widget build(BuildContext context) {return Observer(builder: (_) => Text('${store.count}', style: TextStyle(fontSize: 24)),);}
}

使用方式:

CountText(store: counterStore)

4?? ListView/GridView 中的 Observer

當你需要對列表內容做響應式刷新時,每個 item 可以使用 Observer 包裹。

? 示例:
Observer(builder: (_) => ListView.builder(itemCount: todoStore.todos.length,itemBuilder: (_, index) {final todo = todoStore.todos[index];return Observer(builder: (_) => CheckboxListTile(value: todo.done,onChanged: (_) => todo.toggleDone(),title: Text(todo.title),),);},),
)

每個 CheckboxListTile 都會監聽自己對應的 todo.done,提高效率。


🧠 補充:多層 Observer 嵌套性能說明

MobX 的響應式追蹤是“精確依賴感知”的,每個 Observer 只監聽自己用到的 @observable不會因為 store 中其他字段變化而重建,比傳統 Provider 更細粒度。


? 小結對比
類型優勢適用場景
Observer最常用,自動追蹤通用響應式 UI
Observer + child性能優化靜態元素嵌入 UI
自定義 StatelessWidget 包裹 Observer組件復用通用響應式組件
列表中嵌套 Observer精細追蹤每一項變化todo、商品列表

? MobX 為什么可以“這么做”——原理解析

一、核心機制:可觀察(Observable) + 自動追蹤(Tracking)
  1. @observable 的變量不是普通變量,而是被 MobX 包裝成了 可追蹤對象(Atom)

  2. Observer 被構建時,MobX 開啟一個 “追蹤上下文”(Tracking Context):

    • Observer.builder() 中訪問了哪些 @observable,就自動把這些變量注冊為“依賴”。
  3. 一旦這些依賴發生變化,MobX 會自動通知 Observer 重新構建 UI。


二、過程舉例說明

int count = 0;Observer(builder: (_) => Text('$count'),
)

? MobX 做了什么?

  1. 初次 build 時讀取了 count,MobX 會記錄下這個“讀取動作”:

    “這個 Observer 正在依賴 count!”

  2. 后續調用 count++(即修改 observable)時:

    • MobX 發現 count 改了,它就通知所有依賴 count 的觀察者(也就是這個 Observer)重新執行 builder,從而刷新 UI。

三、MobX 響應式模型的類比

可以把 MobX 的響應式系統類比成:

  • @observable = 數據源(比如“溫度傳感器”)
  • Observer = 顯示模塊(比如“電子溫度計”)
  • MobX = 自動布線系統,知道哪個顯示器監聽哪個傳感器

只要傳感器變化,顯示模塊就刷新。開發者什么都不用手動做。


四、底層依賴追蹤的原理:Atom + Reaction

MobX 的核心類是:

說明
Atom每個 observable 變量都是一個 Atom
Reaction每個 Observer 內部注冊了一個 reaction
Context每次執行 builder() 時,MobX 開啟上下文收集依賴
Derivation指的是任何依賴 observable 的函數,比如 computedObserver

五、Flutter 中 UI 為什么可以重建?

因為 Observer 繼承自 StatelessWidget,而其內部邏輯其實是這樣的(偽代碼):

class Observer extends StatelessWidget {final Reaction _reaction;Observer({required WidgetBuilder builder}) {_reaction = Reaction(() {// 當依賴的 observable 改變時,調用 setState 或 rebuild});}Widget build(BuildContext context) {// 啟動依賴收集_reaction.track(() {builder(context); // 在這個過程中讀取 observable,就會注冊依賴});}
}

? 總結一句話

MobX 可以“這么做”,是因為它在 Observer.builder 執行時自動收集依賴變量,一旦這些變量變化,MobX 會主動通知刷新 UI。你不需要寫 setState,它已經幫你自動“追蹤 + 通知 + 重建”了。


?? 五、自己手寫一個簡化版 MobX(低配實現)

太棒了!下面我就來寫一個低配版的 MobX 響應式系統實現,讓你直觀理解它的底層機制。這個版本包括:

  1. Observable<T>:可觀察變量
  2. Reaction:監聽依賴并自動響應
  3. autorun():一個簡化版的 Observer 行為
  4. 自動依賴追蹤:MobX 的“神操作”

🧠 目標:當你讀取 observable 的時候自動注冊依賴,當你修改 observable 的時候,能觸發依賴函數。


🔧 第一步:實現全局上下文收集機制

typedef VoidCallback = void Function();class ReactiveContext {static final ReactiveContext _instance = ReactiveContext._internal();VoidCallback? _currentReaction;factory ReactiveContext() => _instance;ReactiveContext._internal();void setCurrentReaction(VoidCallback? reaction) {_currentReaction = reaction;}VoidCallback? get currentReaction => _currentReaction;
}

🔮 第二步:實現 Observable

class Observable<T> {T _value;final Set<VoidCallback> _listeners = {};Observable(this._value);T get value {// 自動依賴收集final reaction = ReactiveContext()._currentReaction;if (reaction != null) {_listeners.add(reaction);}return _value;}set value(T newValue) {if (newValue != _value) {_value = newValue;// 通知所有監聽者for (var listener in _listeners) {listener();}}}
}

🔁 第三步:實現 autorun(模擬 Observer)

void autorun(VoidCallback runner) {void wrapped() {ReactiveContext().setCurrentReaction(wrapped); // 注冊當前 reactionrunner();ReactiveContext().setCurrentReaction(null); // 清理}wrapped(); // 初始執行一次,收集依賴
}

🎯 示例:模擬 Counter 自動追蹤 + 響應

void main() {final count = Observable(0);autorun(() {print("當前 count 是:${count.value}");});// 模擬用戶操作count.value = 1; // 自動觸發 autorun 輸出count.value = 2;
}
? 輸出:
當前 count 是:0
當前 count 是:1
當前 count 是:2

🧠 總結:

MobX 組件我們實現的類
@observableObservable<T>
Observerautorun()
依賴追蹤ReactiveContext
reactionVoidCallback 注冊

💡 提升建議:

你可以進一步加上:

  • computed(派生值)
  • action(封裝狀態更新)
  • dispose()(清除監聽)
  • 與 Flutter Widget 結合(如用 ValueListenableBuilder 或自寫 ObserverWidget

🗺 六、MobX 響應流程圖

Observable↓ (讀取)
Reaction ← 自動注冊依賴↓
值變化?↓ 是
刷新 UI(Observer)

(你也可以參考文中附圖,完整展現了 MobX 的響應鏈條)


? 七、總結:MobX 值得用嗎?

MobX 讓狀態管理變得優雅和現代化:

  • 不用寫 setState
  • 不需要 notifyListeners
  • 自動依賴收集
  • 最細粒度響應更新

適合追求響應式編程和簡潔架構的開發者。如果你喜歡 Vue、Svelte 那種“寫了就動”的感覺,MobX 會讓你愛不釋手。


🧰 附加建議

  • 推薦將每個 Store 模塊化、組件化;
  • 可結合依賴注入工具如 GetIt 使用;
  • 想要更復雜管理?可引入 reactionwhen 進行副作用管理。
📚 Flutter 狀態管理系列文章目錄
  1. Flutter 狀態管理(setState、InheritedWidget、 Provider 、Riverpod、 BLoC / Cubit、 GetX 、MobX 、Redux)

  2. setState() 使用詳解:原理及注意事項

  3. InheritedWidget 組件使用及原理

  4. Flutter 中 Provider 的使用、注意事項與原理解析(含代碼實戰)

  5. GetX 用法詳細解析以及注意事項

  6. Flutter BLoC 使用詳細解析

  7. Flutter MobX 響應式原理與實戰詳解

  8. Flutter Riverpod 使用詳細解析

  9. Riverpod原理解析(實現一個自己的Riverpod

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/86848.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/86848.shtml
英文地址,請注明出處:http://en.pswp.cn/web/86848.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

淺談國產數據庫多租戶方案:提升云計算與SaaS的資源管理效率

近年來&#xff0c;“數據庫多租戶”這一概念在技術圈內頻頻出現&#xff0c;成為云計算和SaaS&#xff08;軟件即服務&#xff09;架構中的重要組成部分。多租戶架構不僅為企業提供了高效的資源隔離與共享解決方案&#xff0c;還能大幅降低成本&#xff0c;提高系統的可擴展性…

Wpf的Binding

前言 wpf的Binding就像一個橋梁&#xff0c;它的作用就是連接邏輯層與界面層&#xff0c;既能夠把邏輯層的數據搬到界面層展示&#xff0c;又能將界面層的數據更改后傳遞到邏輯層&#xff0c;Binding的數據來源就是Binding的源&#xff0c;數據展示的地方就是Binding的目標。 …

嵌入式單片機中SPI串行外設接口控制與詳解

串行外設接口(Serial Peripheral Interface)的簡稱也叫做SPI,是一種高速的、全雙工同步通信的一種接口,串行外設接口一般是需要4根線來進行通信(NSS、MISO、MOSI、SCK),但是如果打算實現單向通信(最少3根線),就可以利用這種機制實現一對多或者一對一的通信。 第一:…

【世紀龍科技】新能源汽車動力電池總成裝調與檢修教學軟件

在新能源汽車產業“技術迭代快、安全要求高、實操風險大”的背景下&#xff0c;職業院校如何以“項目式教學改革”為突破口&#xff0c;破解傳統實訓“高成本、高風險、低效率”的困局&#xff1f;江蘇世紀龍科技以桌面VR沉浸式技術為支點&#xff0c;推出《新能源動力電池總成…

GO泛型編程面試題及參考答案

目錄 什么是 Go 中的泛型?Go 從哪個版本開始支持泛型? 在 Go 中如何定義一個帶類型參數的函數? 如何為結構體添加類型參數? 使用 any 關鍵字和自定義類型約束有什么區別? 泛型中~T 的語義及其實際應用是什么? 如何在函數中使用多個類型參數?舉例說明。 Go 泛型支…

ReactRouter-404路由配置以及兩種路由模式

404路由 場景&#xff1a;當瀏覽器輸入url的路徑在整個路由配置中都找不到對應的path&#xff0c;為了用戶體驗&#xff0c;可以使用404兜底組件進行渲染 實現步驟 準備一個404組件在路由表數組的末尾&#xff0c;以*號作為路由path配置路由 新建404組件 const NotFound (…

《Kubernetes》Service 詳解+Ingress

主要介紹kubernetes的流量負載組件&#xff1a;Service和Ingress。 1. Service 1.1 Service介紹 在kubernetes中&#xff0c;pod是應用程序的載體&#xff0c;我們可以通過pod的ip來訪問應用程序&#xff0c;但是pod的ip地址不是固定的&#xff0c;這也就意味著不方便直接采用…

常見網絡知識,寬帶、路由器

常見網絡知識&#xff0c;寬帶、路由器 1、關于光貓、橋接和路由接法 現在的光貓都帶有路由功能&#xff0c;即光貓、路由一體。不需要路由器也能讓設備連上&#xff0c;但是一般來說路由功能穿墻有限&#xff0c;放在弱電箱/多媒體箱里的光貓發射出來的wifi信號其實是很難在…

Android應用緩存清理利器:WorkManager深度實踐指南

本文將帶你全面掌握使用WorkManager實現緩存清理的技術方案&#xff0c;從基礎原理到性能優化&#xff0c;提供完整代碼實現和工程實踐指南 一、緩存清理的必要性與挑戰 在Android應用開發中&#xff0c;緩存管理是優化應用性能的關鍵環節。隨著應用使用時間增長&#xff0c;緩…

如何理解構件“可獨立部署”的特性

構件的“可獨立部署”特性是其區別于普通代碼模塊的核心特征之一&#xff0c;我們可以通過生活案例和技術原理解釋來理解這一特性&#xff1a; 一、生活類比&#xff1a;從“家電維修”看獨立部署 假設你家的空調壞了&#xff0c;維修時只需拆開空調外機更換壓縮機&#xff0…

uni-app subPackages 分包加載:優化應用性能的利器

&#x1f90d; 前端開發工程師、技術日更博主、已過CET6 &#x1f368; 阿珊和她的貓_CSDN博客專家、23年度博客之星前端領域TOP1 &#x1f560; 牛客高級專題作者、打造專欄《前端面試必備》 、《2024面試高頻手撕題》、《前端求職突破計劃》 &#x1f35a; 藍橋云課簽約作者、…

CentOS 8 安裝第二個jdk隔離環境

1.適用于原本已經裝了jdk8&#xff0c;現在需要安裝jdk17&#xff1a; 多版本 JDK 共存不希望修改系統默認 JavaDocker 或腳本化部署 2. 下載 Adoptium&#xff08;原 AdoptOpenJDK&#xff09; 的 OpenJDK 17&#xff1a; cd /指定目錄 sudo wget https://github.com/adopti…

Day.43

getitem方法&#xff1a; class MyList: def __init__(self): self.data [10, 20, 30, 40, 50] def __getitem__(self, idx): return self.data[idx] my_list_obj MyList() print(my_list_obj[2]) len方法&#xff1a; class MyList: def __init__(self): self.data [10…

三七互娛GO面經及參考答案

MySQL 有哪些存儲引擎?MyISAM 如何存儲數字類型數據? MySQL 擁有多種存儲引擎,每種都有其獨特的特性和適用場景。常見的存儲引擎包括 InnoDB、MyISAM、Memory、CSV、Archive、Federated 等。 InnoDB 是 MySQL 5.5 版本之后的默認存儲引擎,它支持事務、外鍵、行級鎖和崩潰恢…

git常見問題匯總-重復提交/刪除已提交文件等問題

git常見問題匯總&#xff1a; 1&#xff0c;已經commit的文件需要修改 /刪除&#xff0c;應該怎么處理&#xff1f; 2&#xff0c;自己建的分支“branch1”顯示“rebasing branch1”&#xff0c;這是什么情況&#xff1f; 3&#xff0c;由于內容修改/優化&#xff0c;在同一個…

Python實例題:簡單的 Web 服務器

目錄 Python實例題 題目 要求&#xff1a; 解題思路&#xff1a; 代碼實現&#xff1a; Python實例題 題目 簡單的 Web 服務器 要求&#xff1a; 使用 Python 的 socket 模塊實現一個簡單的 HTTP 服務器。支持以下功能&#xff1a; 處理 GET 和 POST 請求靜態文件服務…

3.Stable Diffusion WebUI本地部署和實踐

本文看了(68 封私信) 逼真的圖片生產 | Stable Diffusion WebUI本地部署看這一篇就夠了 - 知乎和(68 封私信) Stable Diffusion WebUI 實踐: 基本技法及微調 - 知乎&#xff0c;本人根據它們部署了一遍&#xff0c;中間遇到一些報錯&#xff0c;但根據報錯提示解決了問題&#…

阿里最新開源:Mnn3dAvatar 3D數字人框架, 無需聯網,本地部署可離線運行,支持多模態實時交互

Mnn3dAvatar 3D數字人框架是基于阿里巴巴開源的輕量級深度學習推理框架MNN&#xff08;Mobile Neural Network&#xff09;開發的全新3D數字人框架。Aibot親測這是一個可以在本地運行、完全離線、支持多模態實時交互的智能數字人App。可以在本地私有部署。感興趣的同學可以拿來…

03【C++ 入門基礎】函數重載

文章目錄 引言函數重載函數重載的使用函數重載的原理extern “C” 靜態多態 總結 引言 通過00【C 入門基礎】前言得知&#xff0c;C是為了解決C語言在面對大型項目的局限而誕生&#xff1a; C語言面對的現實工程問題&#xff08;復雜性、可維護性、可擴展性、安全性&#xff0…

改寫一個小項目: flask -------------------> next js

現在&#xff0c;請把上面改寫代碼的過程中&#xff0c;所有的過程&#xff0c;都寫下來&#xff0c;寫為文章的形式&#xff0c;內容比較長&#xff0c;你可以分多次輸出。而且要求語言幽默&#xff0c;苦中作樂的心態。分條理&#xff0c;要清晰。一場從 Flask 到 Next.js 的…