Provider: มันคืออะไร, ตัวจัดการสถานะแอป Flutter

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-02-19 เวลาอ่าน: 7 นาที

Provider — แพ็กเกจการจัดการสถานะสำหรับ Flutter ที่สร้างโดย Remi Rousselet ในปี 2019 เป็นตัวห่อหุ้มเทอบ InheritedWidget Provider แก้ไขปัญหาการส่งข้อมูลลงไปตามต้นไม้ widget โดยไม่ต้องใช้ props drilling widget ใดก็สามารถเข้าถึงสถานะได้ผ่าน context.read<T>() หรือ context.watch<T>() ตาม pub.dev Provider เป็นตัวจัดการสถานะ Flutter ที่ได้รับความนิยมมากที่สุด โดยมีมากกว่า 25 พันไลก์

หัวข้อสำคัญ

  • ChangeNotifier — คลาสที่มี notifyListeners สำหรับแแจ้งผู้สมัครเกี่ยวกับการเปลี่ยนแปลง
  • Consumer — widget ที่สร้างใหม่เมื่อ ChangeNotifier เปลี่ยนแปลง
  • MultiProvider — การรวม Provider หลายตัวโดยไม่ต้องซ้อนกัน
  • ProxyProvider — Provider ที่ขึ้นอยู่กับ Provider อื่น
  • context.read / context.watch — เมธอดสำหรับอ่านสถานะโดยไม่ต้องและด้วยการสมัคร

Provider คืออะไร?

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 และ notifyListeners

ChangeNotifier — คลาสในตัวของ Flutter ที่ใช้รูปแบบ Listener ChangeNotifier แจ้งผู้สมัครเกี่ยวกับการเปลี่ยนแปลงโดยการเรียก notifyListeners() ในบริบทของ Provider ChangeNotifier เป็นคลาหลักสำหรับสถานะ: สร้างคลาสที่สืบทอด ChangeNotifier โดยมีฟิลด์และเมธอดที่เรียก notifyListeners() หลังจากเปลี่ยนแปลงข้อมูล

Dart
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 และ context.watch

Consumer — widget ที่สมัคร ChangeNotifier และสร้างใหม่ในทุกครั้งที่เรียก notifyListeners() Consumer รับฟังก์ชัน builder ที่มีสามพารามิเตอร์: context model child Child — widget ที่ไม่ขึ้นอยู่กับโมเดลและ Consumer ไม่สร้างใหม่ นี่เป็นการเพิ่มประสิทธิภาพ: หาก Consumer มี widget คงที่ (ไอคอน ข้อความที่ไม่มีข้อมูล) จะถูกส่งผ่าน child และไม่ถูกสร้างใหม่

Dart
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 และ ProxyProvider

MultiProvider — widget สำหรับลงทะเบียน Provider หลายตัวโดยไม่ต้องซ้อนกัน แทนที่จะมีต้นไม้ที่มี 5 ระดับของ Provider → Provider → Provider MultiProvider จะรับรายการของผู้ให้บริการ Provider ถัดไปสามารถใช้ตัวก่อนหน้าได้ผ่านคอนสตรักเตอร์ MultiProvider เป็นวิธีมาตรฐานในการจัดระดับรากของแอพพลิเคชัน

Dart
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

Provider ถูกทดสอบ โดยห่อ widget ใน MultiProvider ที่มีค่าทดสอบ ไม่จำเป็นต้องใช้ API หรือฐานข้อมูลจริงสำหรับการทดสอบ — Provider จะถูกแทนที่ด้วยวัตถุจำลอง แพ็กเกจ provider ให้ ProviderScope สำหรับการแยกการทดสอบ — แต่ละการทดสอบจะสร้างต้นไม้ Provider ของตนเองอย่างอิสระ

Dart
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: ประสิทธิภาพและข้อจำกัด

ประสิทธิภาพของ 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 แตกต่างจาก BLoC อย่างไร?

Provider — ตัวห่อหุ้มเทอบ InheritedWidget สำหรับการฉีดการฝงไม้ฝังด้วย ChangeNotifier BLoC — รูปแบบสถาปัตยกรรมที่มี Event + Stream สำหรับการแยกโลจิก Provider เรียนง่ายกว่า BLoC จัดโครงสร้างโค้ดได้เข้มงวดกว่า Provider เหมาะสำหรับแอพพลิเคชันขนาดเล็กและสถานะ UI BLoC สำหรับโลจิกธุรกิจที่ซับซ้อน ตาม Flutter Community 2025 ทั้งสองมักใช้ร่วมกันในโปรเจกต์เดียวกัน

ChangeNotifierProvider คืออะไร?

ChangeNotifierProvider — Provider ประเภทหนึ่งสำหรับอินสแตนซ์ของ ChangeNotifier สร้างวัตถุผ่าน create ให้กับวงศ์สึบทอดและสร้าง Consumer ใหม่เมื่อเรียก notifyListeners ChangeNotifierProvider จะเรียก dispose บน ChangeNotifier โดยอัตโนมัติเมื่อถูกลบออกจากต้นไม้ มีสามวิธีการสร้าง: ChangeNotifierProvider.value (สำหรับวัตถุที่มีอยู่) ChangeNotifierProvider (สำหรับการสร้างแบบเฉื่อยช้า) และ ChangeNotifierProvider.create (สำหรับการสร้างแบบเฉื่อยช้าอย่างชัดเจน)

จะหลีกเลี่ยงการสร้างใหม่ที่ไม่จำเป็นด้วย Provider ได้อย่างไร?

ใช้ context.select แทน context.watch — widget จะสร้างใหม่เมื่อฟีลด์ที่เลือกเปลี่ยนแปลงเท่านั้น แยก ChangeNotifier ขนาดใหญ่ออกเป็นหลายอันเล็ก (หนึ่งโมเดล — หนึ่งความรับผิดชอบ) ใช้ Consumer child สำหรับส่วนที่คงที่ สำหรับรายการ ให้ใช้ ListView.builder กับคีย์ Provider DevTools (Flutter Inspector) แสดงว่า widget ใดบ้างที่สร้างใหม่และเพราะอะไร

สามารถใช้ Provider โดยไม่ต้องใช้ ChangeNotifier ได้หรือไม่?

ได้ Provider (โดยไม่มี ChangeNotifier) — สำหรับฉีดวัตถุที่ไม่สามารถเปลี่ยนแปลงได้ (รีโพซิทอรี่ ไคลเนตา์ API การกำหนดค่า) ValueListenableProvider — สำหรับ ValueNotifier StreamProvider — สำหรับ Stream (Firebase WebSocket) FutureProvider — สำหรับ Future (โหลดการกำหนดค่าตอนเริ่มต้น) ProxyProvider — สำหรับ Provider ที่ขึ้นอยู่กับ Provider อื่น ChangeNotifier จำเป็นเฉพาะสำหรับสถานะที่สามารถเปลี่ยนแปลงได้พร้อมการอัพเดท UI

ProviderNotFoundException คืออะไร?

ProviderNotFoundException — ข้อยกเว้นขณะทำงานที่เกิดขึ้นเมื่อพยายามรับ Provider ที่ไม่ได้ประกาศไว้สูงขึ้นไปในต้นไม้ widget สาเหตุที่พบบ่อย: Provider ถูกประกาศไว้ต่ำกว่า widget ที่พยายามอ่านมัน Provider ถูกประกาศไว้ในเส้นทางหนึ่งและอ่านในอีกเส้นทางหนึ่ง พิมพ์ผิดในประเภท วิธีแก้: ย้าย Provider ขึ้นไปในต้นไม้หรือใช้ MultiProvider ในระดับ MaterialApp สำหรับการฝึงพาทั่วไป

สรุป

  • Provider — ตัวห่อหุ้มเทอบ InheritedWidget สำหรับการจัดการสถานะและ DI ใน Flutter
  • ChangeNotifier — คลาสที่มี notifyListeners สำหรับการอัพเดท UI แบบรีแอกซักเทีฟ
  • Consumer และ context.watch — การสมัครการเปลี่ยนแปลงด้วยการสร้างใหม่โดยอัตโนมัติ
  • MultiProvider — การรวมผู้ให้บริการโดยไม่ต้องซ้อนต้นไม้
  • ProxyProvider — สายโส้การฝึงพาระหว่าง Provider
  • context.select — การสมัครเป้าหมายในฟีลด์เฉพาะของโมเดล
  • StreamProvider และ FutureProvider — การสนับสนุนในตัวสำหรับข้อมูลแบบรีแอกซักเทีฟและแบบพร้อมกัน

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม