Riverpod
State Management package สำหรับ Flutter — แก้ปัญหาการส่ง state ผ่าน constructor ข้าม widget หลายชั้น
ปัญหาที่แก้
เมื่อแอปซับซ้อนขึ้น การส่ง state ผ่าน constructor ทีละชั้น (prop drilling) จะยุ่งยากมาก:
Quiz (เก็บ state)
→ StartScreen (รับ function)
→ QuestionsScreen (รับ function)
→ AnswerButton (รับ function)
→ ...ส่งต่อไปเรื่อยๆ
Riverpod ให้ widget ไหนก็ได้เข้าถึง state ได้ตรงๆ โดยไม่ต้องส่งผ่าน constructor
Setup
# pubspec.yaml
dependencies:
flutter_riverpod: ^2.0.0// main.dart — ห่อ app ด้วย ProviderScope
void main() {
runApp(const ProviderScope(child: MyApp()));
}Provider Types
Provider — ค่าที่ไม่เปลี่ยน
final mealsProvider = Provider((ref) {
return dummyMeals; // ค่าคงที่
});StateNotifierProvider — ค่าที่เปลี่ยนได้ + มี logic
// 1. สร้าง Notifier class
class FavoriteMealsNotifier extends StateNotifier<List<Meal>> {
FavoriteMealsNotifier() : super([]); // เริ่มต้นว่าง
bool toggleMealFavoriteStatus(Meal meal) {
final isExisting = state.contains(meal);
if (isExisting) {
state = state.where((m) => m.id != meal.id).toList();
return false;
} else {
state = [...state, meal]; // สร้าง list ใหม่ ไม่แก้ตัวเดิม
return true;
}
}
}
// 2. สร้าง Provider
final favoriteMealsProvider =
StateNotifierProvider<FavoriteMealsNotifier, List<Meal>>(
(ref) => FavoriteMealsNotifier(),
);สำคัญ: ต้อง assign state ใหม่ทั้งก้อน (ไม่ใช่แก้ list เดิม) → Riverpod ถึงจะรู้ว่า state เปลี่ยน
ใช้ใน Widget
เปลี่ยน StatelessWidget → ConsumerWidget หรือ StatefulWidget → ConsumerStatefulWidget:
class MealsScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
// อ่านค่า + rebuild อัตโนมัติเมื่อ state เปลี่ยน
final favMeals = ref.watch(favoriteMealsProvider);
// เรียก action (ไม่ rebuild)
ref.read(favoriteMealsProvider.notifier).toggleMealFavoriteStatus(meal);
return ListView(
children: favMeals.map((meal) => MealItem(meal: meal)).toList(),
);
}
}ref.watch vs ref.read
ref.watch(provider) | ref.read(provider) | |
|---|---|---|
| ทำอะไร | อ่านค่า + สมัครรับ updates | อ่านค่าครั้งเดียว |
| rebuild | ใช่ — rebuild เมื่อ state เปลี่ยน | ไม่ |
| ใช้ตรงไหน | ใน build() | ใน event handler (onPressed ฯลฯ) |
เปรียบเทียบกับ Lifting State Up
| Lifting State Up | Riverpod | |
|---|---|---|
| เหมาะกับ | แอปเล็ก, 2-3 widget share state | แอปใหญ่, หลาย widget share state |
| วิธีแชร์ | ส่ง function/data ผ่าน constructor | Provider กลาง, widget เข้าถึงตรง |
| ข้อเสีย | prop drilling | ต้องเรียนรู้เพิ่ม |
| setup | ไม่ต้องลง package | ลง flutter_riverpod + ProviderScope |
Key Points
ProviderScopeต้องห่อทั้งแอปในmain()ConsumerWidgetแทนStatelessWidgetเมื่อต้องใช้ providerref.watch()ในbuild()/ref.read()ใน event handler- state ต้อง assign ใหม่ทั้งก้อน (immutable pattern)
- Provider types:
Provider(ค่าคงที่),StateNotifierProvider(ค่าเปลี่ยนได้)
Related
- Flutter — framework ที่ใช้ Riverpod
- State Management — concept ภาพรวม
- Lifting State Up — วิธี share state แบบง่าย (ก่อนจะใช้ Riverpod)
- Widgets — ConsumerWidget เป็น widget type พิเศษ