GetX — ไมโครเฟรมเวิร์กน้ำหนักเบาสำหรับ Flutter ที่รวมการจัดการสถานะ การนำทาง และการฉีดพึ่งพาไว้ในแพ็คเกจเดียว พัฒนาโดย Amir Hossein Abdorashidi GetX นำเสนอ boilerplate ขั้นต่ำ: ไม่ต้องใช้ Stream, ไม่ต้องใช้ ChangeNotifier, ไม่ต้องใช้ BuildContext สำหรับการนำทาง ตามข้อมูลจาก pub.dev GetX มียอดไลก์มากกว่า 13,000 ไลก์ กลายเป็นหนึ่งในแพ็คเกจ Flutter ที่ได้รับความนิยมมากที่สุด
ประเด็นสำคัญ
GetX — ไมโครเฟรมเวิร์กแบบครบวงจรสำหรับ Flutter ที่แก้ปัญหาหลักสามอย่างในการพัฒนา: การจัดการสถานะ การนำทาง (การกำหนดเส้นทาง) และการฉีดพึ่งพา (DI) GetX ไม่ต้องใช้ Stream, ChangeNotifier, Builders หรือการสมัครสมาชิก — ปฏิกิริยาทั้งหมดมีให้โดยตัวห่อ Rx ที่ใช้ GetValue และ GetStream ซึ่งทำงานเร็วกว่า ChangeNotifier หลายสิบเท่า
GetX ถูกวางตำแหน่งเป็นทางเลือกแทนชุด Provider + Navigator + get_it/kiwi แทนที่จะติดตั้งสามแพ็คเกจที่แตกต่างกันและเขียนการกำหนดค่า 10 บรรทัด GetX ให้ทุกอย่างพร้อมใช้งานด้วยบรรทัดเดียว: GetMaterialApp แทน MaterialApp การนำทางทำงานผ่าน Get.to(NextScreen()) โดยไม่ต้องใช้ BuildContext และ DI ทำงานผ่าน Get.put(Service()) โดยไม่ต้องใช้โครงสร้าง Provider
ตาม Flutter Community Survey 2025 พบว่า GetX ถูกใช้ใน 43% ของโปรเจกต์ Flutter เหตุผลหลักในการเลือก: เกณฑ์การเข้าขั้นต่ำ (เรียนรู้ 5 นาที), ไม่มี boilerplate (โค้ดลดลง 60-70% เมื่อเทียบกับ Provider หรือ BLoC) และการพัฒนา MVP ที่รวดเร็ว นักวิจารณ์ชี้ให้เห็นถึงการละเมิดหลักการแยกความรับผิดชอบและความซับซ้อนในการดีบัก
Obx — วิดเจ็ต GetX ปฏิกิริยาที่สร้างใหม่เมื่อตัวแปร Rx เปลี่ยนแปลง Obx ไม่ต้องการการสมัครสมาชิก, dispose หรือฟังก์ชัน Builder — เพียงแค่ห่อวิดเจ็ตใน Obx และใช้ตัวแปร Rx ภายใน Obx จะติดตามโดยอัตโนมัติว่าตัวแปร Rx ใดถูกใช้และวาดใหม่เฉพาะเมื่อมีการเปลี่ยนแปลง
class CounterController extends GetxController {
final count = 0.obs;
void increment() => count++;
}
class CounterScreen extends StatelessWidget {
final controller = Get.put(CounterController());
@override
Widget build(context) => Obx(() => Text('${controller.count}'));
}ตัวแปร Rx: .obs — เก็ตเตอร์ที่ห่อค่าใดๆ ให้เป็นออบเจ็กต์ Rx GetX มีคลาส Rx ที่ระบุชนิด: RxInt, RxString, RxDouble, RxBool, RxList, RxMap ตัวแปร Rx ทั้งหมดทำงานเหมือนพรีมิทีฟทั่วไป: count++, name.value = 'Hello', items.add(item) การเปลี่ยนแปลงจะแจ้งสมาชิก Obx โดยอัตโนมัติ
GetBuilder — ทางเลือกของ Obx ที่ไม่มี Rx ทำงานผ่านการเรียก update() ด้วยตนเอง GetBuilder.filter — สำหรับการอัปเดตเป้าหมายโดยคีย์ ID Obx เร็วกว่า (ติดตามการพึ่งพาอัตโนมัติ) GetBuilder คาดการณ์ได้มากกว่า (เรียกอัปเดตอย่างชัดเจน) แนะนำให้ใช้ Obx สำหรับสถานการณ์ง่ายๆ และ GetBuilder สำหรับวิดเจ็ตที่ซับซ้อนที่มีการพึ่งพาจำนวนมาก
GetxController — คลาสพื้นฐานสำหรับตรรกะทางธุรกิจพร้อมการสนับสนุนวงจรชีวิต GetxController มีเมธอด: onInit() (การเริ่มต้น), onReady() (หลังจากเฟรมแรก), onClose() (การล้างทรัพยากร) แตกต่างจาก ChangeNotifier และ StateNotifier GetxController จัดการการสมัครสมาชิกโดยอัตโนมัติ: เมื่อหน้าถูกทำลาย ตัวแปร Rx และ Workers ทั้งหมดจะถูกยกเลิกการสมัคร
class AuthController extends GetxController {
final user = Rx<User?>(null);
final isLoading = false.obs;
@override
void onInit() {
ever(isLoading, (_) => print('Loading: $isLoading'));
super.onInit();
}
Future<void> login(String email, String password) async {
isLoading.value = true;
user.value = await api.login(email, password);
isLoading.value = false;
}
}Workers — ยูทิลิตี้ปฏิกิริยาของ GetX: ever (เรียกทุกครั้งที่มีการเปลี่ยนแปลง), once (เฉพาะการเปลี่ยนแปลงครั้งแรก), debounce (พร้อมหน่วงเวลา), interval (ไม่เกิน N ครั้งต่อวินาที) Workers แก้ปัญหาทั่วไป: การตรวจสอบฟิลด์ (debounce), การวิเคราะห์ (once), การซิงโครไนซ์ (ever) Workers ยกเลิกการสมัครโดยอัตโนมัติเมื่อเรียก onClose() ป้องกันการรั่วไหลของหน่วยความจำ
การนำทาง GetX ไม่ต้องการ BuildContext ในการเปลี่ยนระหว่างหน้าจอ แทนที่ Navigator.push(context, MaterialPageRoute(...)) ให้ใช้ Get.to(NextScreen()) — เรียกได้จากทุกที่ รวมถึง Controller ที่ไม่สามารถเข้าถึง BuildContext GetX รองรับเส้นทางที่มีชื่อ แอนิเมชัน มิดเดิลแวร์ และการส่งอาร์กิวเมนต์โดยไม่ต้องใช้ MaterialPageRoute
// การนำทางปกติ
Get.to(ProfileScreen());
Get.back();
Get.off(LoginScreen()); // แทนที่เส้นทางปัจจุบัน
Get.offAll(HomeScreen()); // ล้างสแต็ก
// เส้นทางที่มีชื่อ
Get.toNamed('/profile', arguments: 'user123');
Get.offNamed('/login');
// มิดเดิลแวร์
GetPage(
name: '/profile',
page: () => ProfileScreen(),
middlewares: [AuthMiddleware()],
)GetPage และ GetPages: GetX ใช้ GetPages แทน routes ใน MaterialApp Middleware — การตรวจสอบสิทธิ์ การเปลี่ยนเส้นทาง การวิเคราะห์ก่อนเข้าสู่หน้าจอ Transition — แอนิเมชันการเปลี่ยนภาพในตัว: fadeIn, zoom, leftToRight, topToBottom Bindings — คลาสที่เริ่มต้น Controller และการพึ่งพาเมื่อเข้าสู่เส้นทาง Bindings แก้ปัญหาการเริ่มต้นแบบขี้เกียจ: Controller จะถูกสร้างขึ้นเมื่อเปิดหน้าจอเท่านั้น
Get.put — ลงทะเบียนอินสแตนซ์ในคอนเทนเนอร์ DI Get.find — ดึงอินสแตนซ์จากคอนเทนเนอร์ Get.lazyPut — การเริ่มต้นแบบขี้เกียจ (สร้างเมื่อเรียก find ครั้งแรก) Get.putAsync — การเริ่มต้นแบบอะซิงโครนัส (สำหรับบริการที่มี init) Get.delete — ลบออกจากคอนเทนเนอร์ (เรียกโดย Bindings โดยอัตโนมัติเมื่อเส้นทางถูกทำลาย)
| เมธอด | เมื่อถูกสร้าง | เมื่อถูกลบ |
|---|---|---|
| Get.put | ทันที | Get.delete หรือ onClose |
| Get.lazyPut | เมื่อ find ครั้งแรก | Get.delete หรือ onClose |
| Get.putAsync | หลังจาก Future เสร็จสมบูรณ์ | Get.delete หรือ onClose |
| Get.create | ทุกครั้งที่ find (โรงงานใหม่) | ไม่ |
DI ของ GetX — คอนเทนเนอร์ DI ที่ง่ายที่สุดใน Flutter ไม่มีโครงสร้าง Provider, ไม่มี Module, ไม่มี Scope Get.put(Repository()) ใน Controller หรือ main.dart ทำให้ออบเจ็กต์เข้าถึงได้ทุกที่ในแอปผ่าน Get.find<Repository>() DI ของ GetX ยังรองรับ การติดแท็ก (tag: 'api') และ ความถาวร (permanent: true) เพื่อป้องกันการลบ
ประสิทธิภาพของ GetX ขึ้นอยู่กับตัวห่อ Rx ที่ทำงานผ่าน GetStream — การใช้งาน Stream แบบกำหนดเองที่ปรับให้เหมาะกับ Flutter ตามเกณฑ์มาตรฐานของ GetX ตัวแปร Rx เร็วกว่า ChangeNotifier 2-3 เท่าและเร็วกว่า BLoC 5-7 เท่าเมื่อมีการอัปเดตบ่อยครั้ง (30+ fps) GetX ไม่ใช้ BuildContext สำหรับการสมัครสมาชิก ซึ่งช่วยลดการสร้างโครงสร้างวิดเจ็ตใหม่ระหว่างการนำทาง
แนวทางปฏิบัติที่ดีที่สุด: ใช้ GetBuilder แทน Obx สำหรับวิดเจ็ตที่มีองค์ประกอบย่อยจำนวนมาก (รายการ ตาราง) แบ่ง Controller ตามโมดูลฟังก์ชันแทนที่จะเป็น Controller ขนาดใหญ่หนึ่งตัวต่อหน้า ใช้ Bindings สำหรับการเริ่มต้น Controller ไม่ใช่ Get.put ในเมธอด build GetView — StatelessWidget แบบย่อที่มีการเข้าถึง Controller ผ่าน controller โดยไม่ต้องใช้ Get.find
ข้อจำกัดที่ทราบ: GetX ใช้ตัวแปรส่วนกลาง (Get.find, Get.to) ซึ่งอาจทำให้การทดสอบซับซ้อน การจำลองการพึ่งพาผ่าน GetX ต้องใช้ Get.replace() หรือ Get.reset() ระหว่างการทดสอบ สำหรับการแยกส่วน แนะนำให้ใช้ Get.testMode = true ไม่แนะนำให้ใช้ GetX สำหรับแอปพลิเคชันที่ต้องการสถาปัตยกรรมที่เข้มงวดพร้อมขอบเขตชั้นที่ชัดเจน — ในกรณีนี้ BLoC หรือ Riverpod พร้อมการสร้างโค้ดเป็นตัวเลือกที่ดีกว่า
คำถามที่พบบ่อย
GetX — ไมโครเฟรมเวิร์กที่มี DI, การนำทาง และปฏิกิริยา Rx ของตัวเอง Provider — เฉพาะการจัดการสถานะผ่าน ChangeNotifier และ InheritedWidget GetX ไม่ต้องใช้ BuildContext มีการนำทางและ DI ในตัว ลด boilerplate 60-70% Provider ใช้ Flutter Navigator มาตรฐานและต้องการโซลูชันของบริษัทอื่นสำหรับ DI GetX เร็วกว่าในการพัฒนา Provider ใกล้เคียงกับ Flutter API ดั้งเดิมมากกว่า
Workers — ยูทิลิตี้สำหรับการประมวลผลการเปลี่ยนแปลงของตัวแปร Rx แบบปฏิกิริยา ever — คอลแบ็กทุกครั้งที่มีการเปลี่ยนแปลง once — เฉพาะการเปลี่ยนแปลงครั้งแรก debounce — พร้อมหน่วงเวลา (สำหรับฟิลด์ค้นหา) interval — ไม่เกิน N ครั้ง (สำหรับการวิเคราะห์) Workers ประกาศใน onInit() ของ GetxController และยกเลิกการสมัครโดยอัตโนมัติใน onClose() ซึ่งแทนที่ addListener/removeListener ด้วยตนเองกับ ChangeNotifier
GetX มี Get.testMode = true เพื่อเปิดใช้งานโหมดทดสอบ การพึ่งพาจะถูกแทนที่ผ่าน Get.replace<Service>(mockService) ระหว่างการทดสอบ จะเรียก Get.reset() เพื่อล้างคอนเทนเนอร์ DI Controller จะถูกทดสอบโดยตรงโดยไม่ต้องใช้ Flutter: final c = CounterController(); c.increment(); expect(c.count.value, 1) สำหรับวิดเจ็ตที่มี Obx ให้ใช้ tester.pumpWidget ร่วมกับ InjectMocker
GetX เหมาะสำหรับโปรเจกต์ทุกขนาดแต่ต้องมีวินัย สำหรับโปรเจกต์ขนาดใหญ่ (10+ หน้าจอ) ให้ใช้: Bindings สำหรับแยก Controller, โมดูล (ไฟล์ GetPages ต่อคุณลักษณะ), GetView แทน Get.Find ด้วยตนเองใน build ความเสี่ยงหลักคือการใช้การเข้าถึงทั่วโลกในทางที่ผิด (Get.Find ทุกที่) การตรวจสอบโค้ดอย่างเข้มงวดและคำแนะนำทางสถาปัตยกรรมแก้ปัญหานี้ได้ แอปพลิเคชันการผลิตจำนวนมากที่มีผู้ใช้หลายล้านคนทำงานบน GetX
Bindings — คลาสที่เชื่อมต่อเส้นทางกับการพึ่งพาของมัน เมื่อเข้าสู่หน้าจอ Binding จะสร้าง Controller และบริการผ่าน Get.lazyPut และลบออกเมื่อออก Bindings ใช้การเริ่มต้นแบบขี้เกียจ: Controller จะไม่มีอยู่ในหน่วยความจำจนกว่าจะเปิดหน้าจอ ซึ่งช่วยประหยัด RAM และเวลาเริ่มต้นแอป ประกาศใน GetPage: GetPage(name: '/profile', page: () => ProfileScreen(), binding: ProfileBinding())
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ