Provider — แพ็กเกจการจัดการสถานะสำหรับ Flutter ที่สร้างโดย Remi Rousselet ในปี 2019 เป็นตัวห่อหุ้มเทอบ InheritedWidget Provider แก้ไขปัญหาการส่งข้อมูลลงไปตามต้นไม้ widget โดยไม่ต้องใช้ props drilling widget ใดก็สามารถเข้าถึงสถานะได้ผ่าน context.read<T>() หรือ context.watch<T>() ตาม pub.dev Provider เป็นตัวจัดการสถานะ Flutter ที่ได้รับความนิยมมากที่สุด โดยมีมากกว่า 25 พันไลก์
หัวข้อสำคัญ
Provider — แพ็กเกจสำหรับการจัดการสถานะและการฉีดการฝงไม้ฝ่งใน Flutter ที่สร้างบน InheritedWidget Provider ให้วัตถุ (สถานะบริการทุนย์) ในต้นไม้ widget และสร้าง UI ใหม่โดยอัตโนมัติเมื่อข้อมูลเปลี่ยนแปลง แตกต่างจากการใช้ InheritedWidget โดยตรง Provider จะกำจัด boilerplate ทั้งหมด: ไม่จำเป็นต้องเขียนคลาสย่อยของ InheritedWidget ตั้งค่าเมธอดสถานะ of() หรือจัดการการซ้อนกัน
Provider เป็นวิธีที่ Google แนะนำอย่างเป็นทางการสำหรับการจัดการสถานะใน Flutter (Flutter Team 2019-2023) แพ็กเกจนี้เป็นส่วนหนึ่งของ Flutter Ecosystem และได้รับการดูแลโดยทีม Flutter ในช่วงเปิดตัว Provider ถูกเสนอเป็นตัวแทนสำหรับตัวแปรทั่วไปและ InheritedWidget: วัตถุใดก็สามารถเข้าถึงได้จากทุกหมุดโดยไม่ต้องผ่านคอนสตรักเตอร์
ตาม แบบสำรวจชุมชน Flutter 2025 Provider ถูกใช้ใน 72% ของแอปพลิเคชัน Flutter สาเหตุหลักของความนิยมคือ: ข้อกำหนดเข้าต่ำที่สุด การสนับสนุน ChangeNotifier ในตัว ความเข้ากันได้กับสถาปัตยกรรมอื่น (MVVM BLoC) และไม่มีการฝึงพาสรรฉากภายนอก
ChangeNotifier — คลาสในตัวของ Flutter ที่ใช้รูปแบบ Listener ChangeNotifier แจ้งผู้สมัครเกี่ยวกับการเปลี่ยนแปลงโดยการเรียก notifyListeners() ในบริบทของ Provider ChangeNotifier เป็นคลาหลักสำหรับสถานะ: สร้างคลาสที่สืบทอด ChangeNotifier โดยมีฟิลด์และเมธอดที่เรียก notifyListeners() หลังจากเปลี่ยนแปลงข้อมูล
class CounterProvider extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
void reset() {
_count = 0;
notifyListeners();
}
}กฎของ notifyListeners: เรียกหลังจากเปลี่ยนแปลงข้อมูลอย่างสมบูรณ์ — ไม่ใช่กลางทางเมธอด แต่ต่อท้าย หากเมธอดทำการเปลี่ยนแปลงหลายครั้ง ให้เรียก notifyListeners() หนึ่งครั้งหลังจากการเปลี่ยนแปลงทั้งอด ไม่ใช่หลังแต่ละครั้ง ๋นี้ป้องกันการวาดใหม่หลายครั้งในขั้นตอนทางตรรกะเดียว สำหรับการอัพเดทแบบชูด ให้ใช้ notifyListeners ร่วมกับรูปแบบคล้าย setState
ทางเลือกอื่นของ ChangeNotifier: ValueNotifier — สำหรับค่าเดียว (ดีสำหรับประเภทมูลฐาน) StateNotifier — จากแพ็กเกจ state_notifier (ไม่ค่อยใช้เองเดี่ยว) โซลูชัน Provider ส่วนใหญ่ใช้ ChangeNotifier เนื่องจากการสนับสนุนในตัวและความง่าย
Consumer — widget ที่สมัคร ChangeNotifier และสร้างใหม่ในทุกครั้งที่เรียก notifyListeners() Consumer รับฟังก์ชัน builder ที่มีสามพารามิเตอร์: context model child Child — widget ที่ไม่ขึ้นอยู่กับโมเดลและ Consumer ไม่สร้างใหม่ นี่เป็นการเพิ่มประสิทธิภาพ: หาก Consumer มี widget คงที่ (ไอคอน ข้อความที่ไม่มีข้อมูล) จะถูกส่งผ่าน child และไม่ถูกสร้างใหม่
Consumer<CounterProvider>(
builder: (context, provider, child) => Column(
children: [
child!, // ไม่ได้รับการสร้างใหม่
Text('${provider.count}'),
ElevatedButton(
onPressed: () => provider.increment(),
child: Icon(Icons.add),
),
],
),
child: Text('ตัวนับ:'),
)context.watch — เมธอดส่วนขยายของ BuildContext สำหรับสมัคร Provider ส่งคืนโมเดลและสมัคร widget ปัจจุบันในการเปลี่ยนแปลงของมัน context.read — การเข้าถึงโดยไม่ต้องสมัคร (สำหรับตัวจัดการ onPressed initState และ dispose) context.select — การสมัครในฟีลด์เฉพาะของโมเดลโดยไม่ต้องสร้างใหม่เมื่อฟีลด์อื่นเปลี่ยนแปลง Select เป็นตัวเลือกที่มีประสิทธิภาพมากที่สุดสำหรับโมเดลที่ซับซ้อนที่มี 10+ ฟีลด์
เมื่อให้ใช้ Consumer watch หรือ select: Consumer — เมื่อต้องการ widget child สำหรับการเพิ่มประสิทธิภาพ watch — ในเมธอด build สำหรับการอ่านง่าย select — เมื่อโมเดลมีหลายฟีลด์แต่ widget ขึ้นอยู่กับเฉพาะหนึ่ง Provider ยกเลิกการสมัครโดยอัตโนมัติเมื่อ widget ถูกทำลาย ป้องกันการรั่วไหลหน่วยความจำ
MultiProvider — widget สำหรับลงทะเบียน Provider หลายตัวโดยไม่ต้องซ้อนกัน แทนที่จะมีต้นไม้ที่มี 5 ระดับของ Provider → Provider → Provider MultiProvider จะรับรายการของผู้ให้บริการ Provider ถัดไปสามารถใช้ตัวก่อนหน้าได้ผ่านคอนสตรักเตอร์ MultiProvider เป็นวิธีมาตรฐานในการจัดระดับรากของแอพพลิเคชัน
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => CartProvider()),
ChangeNotifierProvider(create: (_) => AuthProvider()),
ProxyProvider<AuthProvider, OrderProvider>(
update: (_, auth, __) => OrderProvider(auth.userId),
),
],
child: MaterialApp(home: HomePage()),
)ProxyProvider — Provider ที่ขึ้นอยู่กับ Provider อื่น ProxyProvider ได้รับค่าจาก Provider อื่นและส่งต่อไปยังวัตถุของมัน ตัวอย่างเช่น OrderProvider ขึ้นอยู่กับ AuthProvider (ต้องการ userId) เมื่อ AuthProvider เปลี่ยนแปลง ProxyProvider จะสร้าง OrderProvider ใหม่โดยอัตโนมัติด้วย userId ใหม่ ChangeNotifierProxyProvider — เวอร์ชัน ProxyProvider สำหรับ ChangeNotifier
StreamProvider และ FutureProvider: StreamProvider สมัคร Stream (Firebase WebSocket) และอัพเดท Consumer ในทุกอีเวนต์ใหม่ FutureProvider — สำหรับการเริ่มต้นแบบพร้อมกัน: รัน Future แสดงการโหลด จากนั้นส่งผลลัพธ์ไปยัง widget ทั้งสองแก้ไขงานทั่วไปโดยไม่ต้องจัดการสมัครด้วยตนเอง
Provider ถูกทดสอบ โดยห่อ widget ใน MultiProvider ที่มีค่าทดสอบ ไม่จำเป็นต้องใช้ API หรือฐานข้อมูลจริงสำหรับการทดสอบ — Provider จะถูกแทนที่ด้วยวัตถุจำลอง แพ็กเกจ provider ให้ ProviderScope สำหรับการแยกการทดสอบ — แต่ละการทดสอบจะสร้างต้นไม้ Provider ของตนเองอย่างอิสระ
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Counter increments on button tap',
(tester) async {
await tester.pumpWidget(
ChangeNotifierProvider(
create: (_) => CounterProvider(),
child: CounterScreen(),
),
);
await tester.tap(find.byKey(Key('increment')));
await tester.pump();
expect(find.text('1'), findsOneWidget);
},
);
}MockProvider: สำหรับการทดสอบ widget ที่มี Provider ซึ่งขึ้นอยู่กับ API ให้สร้างคลาสย่อยจำลองหรือใช้ mockito / mocktail Provider ไม่ต้องการเครื่องมือจำลองพิเศษ — วัตถุใดที่สืบทอด ChangeNotifier สามารถส่งผ่าน create โดยไม่ต้องเรียกบริการจริง โปรแกรม Provider ผ่านอินเตอร์เฟียร์ซ (คลาสนามธรรม) เพื่อการแทนที่ง่าย
ประสิทธิภาพของ Provider ขึ้นอยู่กับ InheritedWidget: เมื่อ Provider เปลี่ยนแปลง widget ทั้งหมดที่สมัครผ่าน context.watch หรือ Consumer จะถูกสร้างใหม่ เพื่อป้องกันการวาดใหม่ที่ไม่จำเป็น ให้ใช้ context.select (การสมัครในฟีลด์เฉพาะ) Consumer กับพารามิเตอร์ child และ const สำหรับ widget คงที่ Provider ไม่สร้างใหม่กิ่งที่ไม่ได้สมัครการเปลี่ยนแปลง
| เมธอด | การสมัคร | การสร้างใหม่ | การใช้งาน |
|---|---|---|---|
| context.watch | โมเดลเต็ม | การเปลี่ยนแปลงใดก็ตาม | Widget ง่าย |
| Consumer | โมเดลเต็ม | การเปลี่ยนแปลงใดก็ตาม | ด้วยการเพิ่มประสิทธิภาพ child |
| context.select | ฟีลด์เฉพาะ | เมื่อฟีลด์เปลี่ยนแปลงเท่านั้น | โมเดลซับซ้อน |
| context.read | ไม่มี | ไม่เคย | ตัวจัดการอีเวนต์ |
ข้อจำกัด: Provider ไม่รองรับการแยกโลจิกธุรกิจในระดับอีเวนต์ (เหมือน BLoC) การเปลี่ยนแปลงทั้งหมดเกิดขึ้นโดยการเรียกวิธีของ ChangeNotifier โดยตรง ซึ่งอาจนำไปสู่โส้ข้อมูลที่ไม่สามารถควบคุมได้ สำหรับสถานการณ์ที่ซับซ้อน (การดำเนินการแบบพร้อมกันหลายรายการตรงสอบที่ซับซ้อน) Provider ด้อยกว่า BLoC และ Riverpod
การย้ายใจจาก Provider: Provider สามารถรวมกับแพ็กเกจอื่นได้ง่าย สำหรับการย้ายไป Riverpod ให้ใช้ ChangeNotifierProvider.adaptive — อะแดปเตอร์ที่ทำให้สามารถใช้ ChangeNotifier ที่มีอยู่กับ Riverpod โดยไม่ต้องเขียนใหม่ สำหรับ BLoC — BlocProvider สามารถวางไว้ภายในต้นไม้ Provider โดยค่อยๆ แทนที่ ChangeNotifier ด้วย Bloc
คำถามที่พบบ่อย
Provider — ตัวห่อหุ้มเทอบ InheritedWidget สำหรับการฉีดการฝงไม้ฝังด้วย ChangeNotifier BLoC — รูปแบบสถาปัตยกรรมที่มี Event + Stream สำหรับการแยกโลจิก Provider เรียนง่ายกว่า BLoC จัดโครงสร้างโค้ดได้เข้มงวดกว่า Provider เหมาะสำหรับแอพพลิเคชันขนาดเล็กและสถานะ UI BLoC สำหรับโลจิกธุรกิจที่ซับซ้อน ตาม Flutter Community 2025 ทั้งสองมักใช้ร่วมกันในโปรเจกต์เดียวกัน
ChangeNotifierProvider — Provider ประเภทหนึ่งสำหรับอินสแตนซ์ของ ChangeNotifier สร้างวัตถุผ่าน create ให้กับวงศ์สึบทอดและสร้าง Consumer ใหม่เมื่อเรียก notifyListeners ChangeNotifierProvider จะเรียก dispose บน ChangeNotifier โดยอัตโนมัติเมื่อถูกลบออกจากต้นไม้ มีสามวิธีการสร้าง: ChangeNotifierProvider.value (สำหรับวัตถุที่มีอยู่) ChangeNotifierProvider (สำหรับการสร้างแบบเฉื่อยช้า) และ ChangeNotifierProvider.create (สำหรับการสร้างแบบเฉื่อยช้าอย่างชัดเจน)
ใช้ context.select แทน context.watch — widget จะสร้างใหม่เมื่อฟีลด์ที่เลือกเปลี่ยนแปลงเท่านั้น แยก ChangeNotifier ขนาดใหญ่ออกเป็นหลายอันเล็ก (หนึ่งโมเดล — หนึ่งความรับผิดชอบ) ใช้ Consumer child สำหรับส่วนที่คงที่ สำหรับรายการ ให้ใช้ ListView.builder กับคีย์ Provider DevTools (Flutter Inspector) แสดงว่า widget ใดบ้างที่สร้างใหม่และเพราะอะไร
ได้ Provider (โดยไม่มี ChangeNotifier) — สำหรับฉีดวัตถุที่ไม่สามารถเปลี่ยนแปลงได้ (รีโพซิทอรี่ ไคลเนตา์ API การกำหนดค่า) ValueListenableProvider — สำหรับ ValueNotifier StreamProvider — สำหรับ Stream (Firebase WebSocket) FutureProvider — สำหรับ Future (โหลดการกำหนดค่าตอนเริ่มต้น) ProxyProvider — สำหรับ Provider ที่ขึ้นอยู่กับ Provider อื่น ChangeNotifier จำเป็นเฉพาะสำหรับสถานะที่สามารถเปลี่ยนแปลงได้พร้อมการอัพเดท UI
ProviderNotFoundException — ข้อยกเว้นขณะทำงานที่เกิดขึ้นเมื่อพยายามรับ Provider ที่ไม่ได้ประกาศไว้สูงขึ้นไปในต้นไม้ widget สาเหตุที่พบบ่อย: Provider ถูกประกาศไว้ต่ำกว่า widget ที่พยายามอ่านมัน Provider ถูกประกาศไว้ในเส้นทางหนึ่งและอ่านในอีกเส้นทางหนึ่ง พิมพ์ผิดในประเภท วิธีแก้: ย้าย Provider ขึ้นไปในต้นไม้หรือใช้ MultiProvider ในระดับ MaterialApp สำหรับการฝึงพาทั่วไป
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ