2026 年的某一天,當你打開 https://github.com/jonataslaw/getx,迎接你的不是那個熟悉的 10000+ star 的倉庫,而是一個冰冷的 404 頁面。

不只是倉庫。作者 jonataslaw(Jonny Borges)的整個 GitHub 首頁也 404 了。get_cli、get_server、get_storage——整個 GetX 生態的所有倉庫,一夜之間全部消失。
沒有告別信,沒有遷移公告,沒有「專案已封存」的標註。一個曾經是 Flutter 社群最具爭議、也最廣泛使用的第三方套件,就這樣無聲無息地消失了。
pub.dev 上的 get 套件還在——因為 pub.dev 是獨立托管的,不會因為 GitHub 刪庫而下架。你的專案今天還能 flutter pub get,還能編譯、還能執行。但原始碼沒了,Issue 沒了,786 個未關閉的 Issue 沒了,78 個待合併的 PR 沒了,文件沒了。
一個沒有原始碼倉庫的套件,和一具沒有靈魂的軀殼有什麼區別?
在說「為什麼不用」之前,先承認一個事實:GetX 確實火過。並且號稱宇宙第一:

它火是有原因的。看這段程式:
// 傳統方式:定義 StatefulWidget,寫 setState,管理生命週期
class CounterPage extends StatefulWidget {
@override
_CounterPageState createState() => _CounterPageState();
}
class _CounterPageState extends State<CounterPage> {
int count = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Text('$count')),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => count++),
child: Icon(Icons.add),
),
);
}
}
// GetX 方式:三行搞定
final count = 0.obs;
Obx(() => Text('$count'));
onPressed: () => count++;
對於剛入門 Flutter 的開發者來說,這種簡潔性有致命的吸引力。「為什麼要寫那麼多樣板程式?GetX 三行就搞定了。」
但「簡潔」和「簡單」不是一回事。簡潔是表面上程式少,簡單是底層複雜度低。GetX 的程式少,但底層複雜度一點都不低——它只是把複雜度藏起來了。
從 2018 年開始寫 Flutter,到現在 8 年了。期間無數次被推薦 GetX,無數次在技術群裡看到「用 GetX 三行程式搞定」的安利。但我一次都沒用過。甚至我的群組公告裡都寫著:
本群禁止討論 GetX,有任何問題可以向 GetX 官方提 Issue。
不是因為我有先見之明,而是因為它違反了我認為正確的幾個原則。
GetX 管了你的狀態、路由、依賴注入、國際化、主題、HTTP 請求、本地儲存、表單驗證……一個套件解決所有問題,聽起來很美。
但軟體工程的基本常識是:耦合越緊,風險越大。來看一個真實的對比:
# 方案 A:每層獨立
dependencies:
provider: ^6.0.0 # 狀態管理
go_router: ^14.0.0 # 路由
dio: ^5.0.0 # 網路請求
shared_preferences: ^2.0.0 # 本地儲存
intl: ^0.19.0 # 國際化
# 方案 B:全家桶
dependencies:
get: ^4.7.3 # 狀態 + 路由 + DI + 網路 + 存儲 + 國際化 + ...
方案 A 看起來依賴多,但每個依賴都是獨立的。dio 不維護了?換成 http,其他四個完全不受影響。路由庫想升級?只改路由層,狀態管理一行不用動。
方案 B 看起來清爽,只有一個依賴。但這個依賴出問題 = 所有東西出問題。
今天,這個「所有東西出問題」的場景真的發生了。
GetX 最大的賣點之一是「不需要 context」。Get.find() 可以在程式的任何角落呼叫,不需要 Widget 樹,不需要建構式參數。
// GetX 的方式:在任何地方都能拿到任何東西
class OrderController extends GetxController {
void submitOrder() {
// 這三個依賴從哪來的?誰註冊的?什麼時候註冊的?生命週期是什麼?
final cart = Get.find<CartController>();
final auth = Get.find<AuthController>();
final api = Get.find<ApiService>();
// ...
}
}
// 官方推薦方式:依賴透過建構式顯式傳入
class OrderViewModel extends ChangeNotifier {
final CartRepository _cartRepository;
final AuthRepository _authRepository;
// 一眼就知道依賴了什麼,測試時直接傳 Fake
OrderViewModel({
required CartRepository cartRepository,
required AuthRepository authRepository,
}) : _cartRepository = cartRepository,
_authRepository = authRepository;
}
寫起來確實多了幾行。但代價是什麼?
Get.find():只有在執行時全域容器註冊好後才會成功,刪掉一個註冊也許編譯仍通過但執行時會崩潰這不是「風格偏好」,這是編譯時安全 vs 執行時崩潰的根本差異。一個專案有 50 個 Controller,每個都用 Get.find() 拿依賴,你敢重構嗎?
GetX 本質上是個人的專案。jonataslaw 一個人寫了狀態管理、路由、依賴注入、HTTP 客戶端、國際化、主題……一個人維護這麼大範圍,品質和持續性都無法保證。
早在刪庫之前,訊號就已經很明顯了:
對比一下其他方案的維護情況:
provider:Flutter 官方團隊支持,維護穩定go_router:有官方或大型貢獻者支持ChangeNotifier:內建於 Flutter 框架flutter_bloc:社群多人維護,風險低riverpod:由 Remi Rousselet(provider 作者)主導,社群活躍GetX 的情況是:核心維護者只有一人,且已經發生了倒閉式的消失。
GetX 的宣傳語之一是「不需要 context 就能導航、彈對話框、顯示 SnackBar」。
// GetX:不需要 context
Get.to(HomePage());
Get.snackbar('標題', '內容');
Get.dialog(AlertDialog(...));
聽起來很方便。但 context 在 Flutter 裡不是累贅——它是 Widget 樹的定位器,告訴框架「我在哪裡」。繞過 context 意味著繞過 Flutter 的 Widget 生命週期管理,這會導致:
GetX 用全域狀態和靜態方法繞過了 Flutter 的設計,短期內寫起來爽,長期維護時各種幽靈 Bug 會讓你抓狂。
如果你的專案正在用 GetX,不要恐慌,但也不要心存僥倖。
短期內你是安全的:
pubspec.lock 已鎖定版本,flutter pub get 仍可運作但定時炸彈已經埋下了:
不要一次性重寫。逐層替換,每次只動一個模組,每次都跑測試:
路由(影響範圍最小,最先下手)
Get.toNamed('/home') → 使用 GoRouter 的宣告式路由Get.back() → context.pop()(或 Navigator.of(context).pop())GetPage → GoRoute依賴注入(把隱式改成顯式)
Get.put(MyController()) → ChangeNotifierProvider(create: (_) => MyViewModel())Get.find<MyController>() → context.read<MyViewModel>()Get.lazyPut(...) → Provider 的 lazy 行為或使用其他 DI 工具(如 get_it)狀態管理(工作量最大,但收益也最大)
GetxController + .obs + Obx → ChangeNotifier + Consumer / context.watchupdate() → notifyListeners()GetBuilder → Consumer其他零散功能
GetConnect → dio / httpflutter_localizations + ARB 檔案ThemeData + ThemeModeGet.snackbar() → ScaffoldMessenger.of(context).showSnackBar()Get.dialog() → showDialog(context: context, ...)每完成一步,就執行一次測試,確認沒有回歸。如果你的專案沒有測試——這是另一項需要補的債,而且優先度比遷移 GetX 還高。
如果是大專案,建議新功能以新方案開發,舊功能逐步遷移,不要停下業務開發來專門做一次性全面遷移。
GetX 之死不是個案。它揭示了開源生態中的一個結構性風險:社群的繁榮可以掩蓋專案的脆弱性。
10,000+ star、數十種語言的 README 翻譯、數百個教學影片——這些都是社群繁榮的表現。但專案的健康度不取決於 star 數,而取決於:
下次選擇第三方套件時,不要只看 star 與 likes。打開 GitHub 倉庫,看看:
如果一個套件只有一個核心維護者、半年沒有 commit、幾百個未關閉的 Issue——不管它有多少 stars,都要三思。
GetX 退場後,Flutter 狀態管理的格局更清晰了:
| 方案定位 | 適合誰 | 維護狀況 |
|---|---|---|
| provider + ChangeNotifier | Flutter 官方推薦的入門方案 | 大多數專案,官方維護良好 |
| Riverpod | provider 的進化版,編譯時安全 | 追求類型安全和可測試性的專案,社群活躍,多人維護 |
| flutter_bloc / Cubit | 企業級方案,嚴格的單向資料流 | 大型專案、需要稽核追蹤的場景,社群活躍 |
| setState | 最簡單的方式 | 臨時狀態、原型開發,框架內建,永遠不會消失 |
沒有 GetX,以後也不會再有 GetX(指那種由單一維護者承擔整個「全家桶」功能並且極度隱式依賴的情況)。
8 年前我選擇不用 GetX,不是因為預見了今天,而是因為幾個樸素的判斷:
今天這些判斷被驗證了。但我並不覺得高興——畢竟有大量的專案和開發者受到影響。那些用 GetX 寫了數萬行程式的團隊,現在面對的是一個沒有原始碼、沒有維護者、沒有未來的核心依賴。
如果你正在選擇 Flutter 的技術棧,記住一條原則:
每一層都應該可以獨立替換。
狀態管理、路由、依賴注入、網路請求——每一層用獨立的方案,每一層都有替代品。這樣無論哪一層出問題,你只需要換那一層,而不是重寫整個應用。
這不是過度設計,這是基本的風險管理。
GetX 教會了我們:在開源世界裡,便利是借來的,風險是自己的。
筆者目前在公眾號「編程之王」撰寫並發布《Flutter Agent Skills 全解析》系列,涵蓋 Flutter 官方推薦的 22 個開發技能。如果你對 Flutter 官方推薦的架構、狀態管理、測試等最佳實踐感興趣,歡迎關注。