- ภาพรวม (Overview) ของการจัดการสถานะ (State) ใน Flutter
- Provider
- Bloc/Cubit
- Redux
- ริเวอร์พอด (Riverpod)
การจัดการสถานะ (State Management) เป็นส่วนสำคัญของการรับทำแอพใดๆ เพื่อให้แน่ใจว่าการจัดการข้อมูลที่ราบรื่นและมีประสิทธิภาพ ใน Flutter มีเทคนิคการจัดการสถานะที่หลากหลาย ซึ่งแต่ละเทคนิคมีข้อดีและกรณีการใช้งาน บทความนี้จะสำรวจโซลูชันการจัดการสถานะยอดนิยมใน Flutter ซึ่งรวมถึง Provider, Bloc/Cubit, Redux และ Riverpod เพื่อช่วยให้คุณมีข้อมูลประกอบการตัดสินใจสำหรับการทำแอพของคุณ
1. ภาพรวม (Overview) ของการจัดการสถานะ (State) ใน Flutter
การจัดการสถานะ (State Management) หมายถึงการจัดการข้อมูลและการเปลี่ยนแปลง UI ในลักษณะที่สอดคล้องและมีประสิทธิภาพ ใน Flutter วิดเจ็ตเปลี่ยนรูปไม่ได้ ซึ่งหมายความว่าคุณสมบัติไม่สามารถเปลี่ยนแปลงได้โดยตรง ด้วยเหตุนี้ การจัดการสถานะของแอพจึงมีความสำคัญต่อการแสดงการเปลี่ยนแปลงใน UI เทคนิคการจัดการสถานะที่สำคัญใน Flutter ได้แก่:
- setState(): เทคนิคการจัดการสถานะโลคัลที่ใช้สำหรับสถานการณ์ง่ายๆ ภายในวิดเจ็ตเดียว
- InheritedWidget: วิธีเผยแพร่ข้อมูลในแผนผังวิดเจ็ต
- ScopedModel: แพ็คเกจของบุคคลที่สามที่ให้แนวทางตามแบบจำลอง
- Provider: โซลูชันการจัดการสถานะยอดนิยมและยืดหยุ่น
- Bloc/Cubit: แนวทางที่มีประสิทธิภาพสำหรับการทำแอพขนาดใหญ่ โดยแยกตรรกะทางธุรกิจออกจาก UI
- Redux: คอนเทนเนอร์สถานะที่คาดเดาได้จากการไหลของข้อมูลทิศทางเดียว
- Riverpod: ทางเลือกที่ทรงพลัง ยืดหยุ่น และปลอดภัยสำหรับ Provider
2. Provider
Provider เป็นโซลูชันการจัดการสถานะที่ได้รับความนิยมและยืดหยุ่นซึ่งสร้างขึ้นจาก InheritedWidget ทำให้กระบวนการเข้าถึงและแก้ไขข้อมูลทั่วทั้งแอพของคุณง่ายขึ้นโดยการเปิดเผยออบเจกต์ไปยังแผนผังวิดเจ็ต Provider มีข้อดีหลายประการ ได้แก่ :
- ติดตั้งง่ายและรหัสสำเร็จรูปน้อยที่สุด (minimal boilerplate code)
- ความสามารถในการปรับขนาดสำหรับการใช้งานทั้งขนาดเล็กและขนาดใหญ่
- การสนับสนุน Dependency injection
หากต้องการใช้ Provider ให้ทำตามขั้นตอนเหล่านี้:
- เพิ่มแพ็คเกจ ‘Provider’ ลงใน
pubspec.yaml
ไฟล์ ของคุณ - สร้างคลาสแบบจำลองเพื่อแสดงข้อมูลของคุณ
- ล้อมแผนผังวิดเจ็ตของคุณในไฟล์
ChangeNotifierProvider
. - เข้าถึงและ แก้ไขข้อมูลโดยใช้
Provider.of()
หรือConsumer
ตัวอย่าง: การใช้แอพตัวนับโดยใช้ Provider
ในตัวอย่างนี้ เราจะใช้การทำแอพตัวนับอย่างง่ายโดยใช้แพ็คเกจ Provider สำหรับการจัดการสถานะ แอพจะมีปุ่มเพื่อเพิ่มตัวนับและแสดงจำนวนที่อัปเดต
1. เพิ่มแพ็คเกจ ‘provider’ ลงใน pubspec.yaml
ไฟล์ของคุณ:
dependencies:
flutter:
sdk: flutter
provider: ^6.0.1
2. สร้างคลาสโมเดล CounterModel
ที่ขยาย (extends) ChangeNotifier
เพื่อแสดงข้อมูลตัวนับของคุณ:
import 'package:flutter/foundation.dart';
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
3. ห่อหุ่ม (wrap) วิดเจ็ตของคุณใน ChangeNotifierProvider:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'counter_model.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => CounterModel(),
child: MaterialApp(
home: CounterScreen(),
),
);
}
}
4. เข้าถึงและแก้ไขข้อมูลโดยใช้ Provider.of()
หรือ Consumer
ใน CounterScreen
:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'counter_model.dart';
class CounterScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Counter App')),
body: Center(
child: Consumer<CounterModel>(
builder: (context, counter, child) {
return Text(
'Count: ${counter.count}',
style: TextStyle(fontSize: 24),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Provider.of<CounterModel>(context, listen: false).increment();
},
child: Icon(Icons.add),
),
);
}
}
ในตัวอย่างนี้ เราใช้ ChangeNotifierProvider
จัดเตรียมอินสแตนซ์ของ CounterModel
ให้กับแผนผังวิดเจ็ต จากนั้นเราใช้ Consumer
วิดเจ็ตเพื่อเข้าถึงและแสดงจำนวนปัจจุบัน สุดท้าย เรา.ใช้ Provider.of()
เพิ่มจำนวนเมื่อผู้ใช้แตะปุ่ม FloatingActionButton
3. Bloc/Cubit
Bloc (องค์ประกอบตรรกะทางธุรกิจ) และ Cubit เป็นโซลูชันการจัดการสถานะขั้นสูงที่แยกตรรกะทางธุรกิจออกจาก UI พวกเขาบังคับใช้การไหลของข้อมูลทิศทางเดียว ทำให้การทำแอพ Flutter ของคุณสามารถคาดเดาได้มากขึ้นและบำรุงรักษาง่ายขึ้น ความแตกต่างที่สำคัญระหว่าง Bloc และ Cubit คือ:
- Bloc ขับเคลื่อนด้วยเหตุการณ์ ในขณะที่ Cubit ขับเคลื่อนด้วยฟังก์ชัน
- Bloc ใช้
Stream
สำหรับการเปลี่ยนแปลงสถานะ ในขณะที่ Cubit ใช้StateNotifier
.
หากต้องการใช้ Bloc/Cubit ให้ทำตามขั้นตอนเหล่านี้:
- เพิ่มแพ็คเกจ ‘flutter_bloc’ ลงใน
pubspec.yaml
ไฟล์ ของคุณ - สร้างคลาส Bloc หรือ Cubit เพื่อจัดการสถานะของแอพ
- ใช้ตรรกะในการจัดการเหตุการณ์ (Bloc) หรือฟังก์ชัน (Cubit)
- ล้อมแผนผังวิดเจ็ ตของคุณใน
BlocProvider
หรือCubitProvider
- เข้าถึงและแก้ไขสถานะโดยใช้
BlocBuilder
,BlocListener
,context.read()
หรือ
ตัวอย่าง: การใช้แอพรายการสิ่งที่ต้องทำโดยใช้ Bloc/Cubit
ในตัวอย่างนี้ เราจะใช้การทำแอพรายการสิ่งที่ต้องทำอย่างง่ายโดยใช้แพ็คเกจ Bloc/Cubit สำหรับการจัดการสถานะ แอพจะอนุญาตให้ผู้ใช้เพิ่มงานใหม่และสลับสถานะการเสร็จสิ้นของแต่ละงาน
1. เพิ่มแพ็คเกจ ‘flutter_bloc’ ในpubspec.yaml
ไฟล์ของคุณ:
dependencies:
flutter:
sdk: flutter
flutter_bloc: ^8.0.1
2. สร้างคลาส Cubit TodoCubit
เพื่อจัดการสถานะของแอพของคุณ:
import 'package:bloc/bloc.dart';
class Todo {
final String title;
bool isCompleted;
Todo({required this.title, this.isCompleted = false});
}
class TodoCubit extends Cubit<List<Todo>> {
TodoCubit() : super([]);
void addTask(String title) {
final newTask = Todo(title: title);
emit([...state, newTask]);
}
void toggleTaskCompletion(int index) {
state[index].isCompleted = !state[index].isCompleted;
emit([...state]);
}
}
3. ล้อมแผนผังวิดเจ็ตของคุณใน BlocProvider
:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'todo_cubit.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => TodoCubit(),
child: MaterialApp(
home: TodoListScreen(),
),
);
}
}
4. เข้าถึงและแก้ไขสถานะโดยใช้ BlocBuilder
และcontext.read()
ใน TodoListScreen
:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'todo_cubit.dart';
class TodoListScreen extends StatelessWidget {
final TextEditingController _textController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('To-Do List')),
body: BlocBuilder<TodoCubit, List<Todo>>(
builder: (context, todos) {
return ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
final todo = todos[index];
return ListTile(
title: Text(todo.title),
trailing: Checkbox(
value: todo.isCompleted,
onChanged: (_) {
context.read<TodoCubit>().toggleTaskCompletion(index);
},
),
);
},
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
final title = await _showAddTaskDialog(context);
if (title != null && title.isNotEmpty) {
context.read<TodoCubit>().addTask(title);
}
},
child: Icon(Icons.add),
),
);
}
Future<String?> _showAddTaskDialog(BuildContext context) {
return showDialog<String>(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Add Task'),
content: TextField(
controller: _textController,
decoration: InputDecoration(hintText: 'Task title'),
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(_textController.text.trim());
},
child: Text('Add'),
),
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Cancel'),
),
],
);
},
);
}
}
ในตัวอย่างนี้ เราใช้ BlocProvider เพื่อจัดเตรียมอินสแตนซ์ของ TodoCubit ให้กับแผนผังวิดเจ็ต จากนั้นเราก็ใช้ BlocBuilder วิดเจ็ตเพื่อเข้าถึงและแสดงรายการงาน นอกจากนี้ เรายังใช้context.read()
เพื่อเพิ่มงานใหม่และสลับสถานะการเสร็จสิ้นเมื่อผู้ใช้โต้ตอบกับแอพ
ใน TodoListScreen
, เราสร้าง ListView เพื่อแสดงงานและใช้ ListTile เพื่อแสดงชื่องานและสถานะความสมบูรณ์ของงานแต่ละรายการ FloatingActionButton เปิดกล่องโต้ตอบเพื่อป้อนชื่องาน และเมื่อผู้ใช้เพิ่มงานใหม่ เราจะเรียกcontext.read<TodoCubit>().addTask(title)
ให้อัปเดตสถานะ
ใน _showAddTaskDialog
วิธีการ เราสร้าง AlertDialog ด้วย TextField เพื่อให้ผู้ใช้ป้อนชื่องาน ปุ่ม ‘เพิ่ม’ จะเพิ่มงานไปยังรายการสิ่งที่ต้องทำ ในขณะที่ปุ่ม ‘ยกเลิก’ จะยกเลิกกล่องโต้ตอบโดยไม่เพิ่มงานใหม่
ด้วยการใช้การทำแอพ Flutter รายการสิ่งที่ต้องทำโดยใช้แพ็คเกจ Bloc/Cubit เราสามารถแยกตรรกะทางธุรกิจออกจาก UI และรักษาการไหลของข้อมูลทิศทางเดียว ทำให้แอพคาดการณ์ได้มากขึ้นและบำรุงรักษาง่ายขึ้น
4. Redux
Redux เป็นคอนเทนเนอร์สถานะที่คาดเดาได้ซึ่งได้รับแรงบันดาลใจจากสถาปัตยกรรม Flux มันบังคับใช้การไหลของข้อมูลทิศทางเดียวและส่งเสริมกระบวนทัศน์การเขียนโปรแกรมการทำงาน Redux มีข้อดีหลายประการ ได้แก่ :
- การจัดการของรัฐแบบรวมศูนย์
- ตรวจแก้จุดบกพร่องและทดสอบได้ง่าย
- การดีบักการเดินทางข้ามเวลา
หากต้องการใช้ Redux ใน Flutter ให้ทำตามขั้นตอนเหล่านี้:
- เพิ่มแพ็คเกจ ‘flutter_redux’ ลงในpubspec.yamlไฟล์ ของคุณ
- สร้างร้านค้าเพื่อเก็บสถานะ การดำเนินการ และตัวย่อของแอพ
- กำหนดสถานะแอพ การดำเนินการ และตัวลดขนาด
- ล้อมแผนผังวิดเจ็ตของคุณในไฟล์StoreProvider.
- เข้าถึงและแก้ไขสถานะโดยใช้StoreConnector, store.dispatch(), store.state
ตัวอย่าง: การใช้แอพตะกร้าสินค้าโดยใช้ Redux
ในตัวอย่างนี้ เราจะสาธิตวิธีใช้การทำแอพตะกร้าสินค้าอย่างง่ายโดยใช้ Redux สำหรับการจัดการสถานะใน Flutter
- เพิ่ม dependencies
เพิ่ม flutter_redux
และ redux
แพ็คเกจลงใน pubspec.yaml
ไฟล์ของคุณ:
dependencies:
flutter:
sdk: flutter
flutter_redux: ^0.8.2
redux: ^5.0.0
- กำหนดสถานะของแอพ (app state)
สร้าง models
โฟลเดอร์และเพิ่ม product.dart
ไฟล์สำหรับรุ่นผลิตภัณฑ์:
class Product {
final String id;
final String name;
final double price;
Product({required this.id, required this.name, required this.price});
}
จากนั้น สร้าง app_state.dart
ไฟล์เพื่อกำหนดสถานะของแอพ (app state):
import 'package:shopping_cart/models/product.dart';
class AppState {
final List<Product> products;
AppState({required this.products});
AppState.initialState() : products = List<Product>.unmodifiable([]);
}
- กำหนด actions
สร้าง actions
โฟลเดอร์และเพิ่ม cart_actions.dart
ไฟล์เพื่อกำหนดการดำเนินการของรถเข็น:
import 'package:shopping_cart/models/product.dart';
class AddToCartAction {
final Product product;
AddToCartAction({required this.product});
}
class RemoveFromCartAction {
final Product product;
RemoveFromCartAction({required this.product});
}
- กำหนดตัวลด (reducers)
สร้าง reducers
โฟลเดอร์และเพิ่ม cart_reducer.dart
ไฟล์เพื่อกำหนดตัวลดรถเข็น:
import 'package:shopping_cart/models/app_state.dart';
import 'package:shopping_cart/actions/cart_actions.dart';
AppState appReducer(AppState state, dynamic action) {
if (action is AddToCartAction) {
return AppState(products: [...state.products, action.product]);
} else if (action is RemoveFromCartAction) {
return AppState(products: state.products.where((product) => product.id != action.product.id).toList());
}
return state;
}
- ตั้งค่าร้านค้า Redux
ใน main.dart
ไฟล์ของคุณ ให้ตั้งค่าที่เก็บ Redux และรวม MaterialApp
วิดเจ็ตของคุณใน StoreProvider
:
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
import 'package:shopping_cart/models/app_state.dart';
import 'package:shopping_cart/reducers/cart_reducer.dart';
void main() {
final store = Store<AppState>(
appReducer,
initialState: AppState.initialState(),
);
runApp(MyApp(store: store));
}
class MyApp extends StatelessWidget {
final Store<AppState> store;
MyApp({required this.store});
@override
Widget build(BuildContext context) {
return StoreProvider<AppState>(
store: store,
child: MaterialApp(
title: 'Shopping Cart',
theme: ThemeData(primarySwatch: Colors.blue),
home: ShoppingCart(),
),
);
}
}
- สร้าง UI และเชื่อมต่อกับ Redux
สร้าง shopping_cart.dart
ไฟล์เพื่อสร้าง UI ของแอพและเชื่อมต่อกับ Redux โดยใช้ StoreConnector
:
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:shopping_cart/actions/cart_actions.dart';
import 'package:shopping_cart/models/app_state.dart';
import 'package:shopping_cart/models/product.dart';
class ShoppingCart extends StatelessWidget {
final List<Product> products = [
Product(id: '1', name: 'Product 1', price: 10.0),
Product(id: '2', name: 'Product 2', price: 20.0),
Product(id: '3', name: 'Product 3', price: 30.0),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Shopping Cart')),
body: ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
final product = products[index];
return ListTile(
title: Text(product.name),
subtitle: Text('\$${product.price}'),
trailing: StoreConnector<AppState, VoidCallback>(
converter: (store) {
return () => store.dispatch(AddToCartAction(product: product));
},
builder: (_, callback) {
return IconButton(
icon: Icon(Icons.add_shopping_cart),
onPressed: callback,
);
},
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return StoreConnector<AppState, List<Product>>(
converter: (store) => store.state.products,
builder: (_, cartProducts) {
return AlertDialog(
title: Text('Your Cart'),
content: cartProducts.isNotEmpty
? Column(
mainAxisSize: MainAxisSize.min,
children: cartProducts.map((product) {
return ListTile(
title: Text(product.name),
subtitle: Text('\$${product.price}'),
trailing: StoreConnector<AppState, VoidCallback>(
converter: (store) {
return () => store.dispatch(RemoveFromCartAction(product: product));
},
builder: (_, callback) {
return IconButton(
icon: Icon(Icons.remove_shopping_cart),
onPressed: callback,
);
},
),
);
}).toList(),
)
: Center(child: Text('Your cart is empty')),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('Close'),
),
],
);
},
);
},
);
},
tooltip: 'View Cart',
child: Icon(Icons.shopping_cart),
),
);
}
}
แอพตะกร้าสินค้าที่แสดงที่นี่แสดงให้เห็นถึงการใช้ Redux สำหรับการจัดการสถานะใน Flutter โดยจะแสดงรายการสินค้าที่ช่วยให้ผู้ใช้สามารถเพิ่มสินค้าลงในรถเข็นหรือลบออกได้โดยแตะที่ไอคอนที่เกี่ยวข้อง เมื่อกดปุ่มการทำงานแบบลอยตัว รถเข็นจะปรากฏเป็นโมดอล
5. ริเวอร์พอด (Riverpod)
Riverpod เป็นทางเลือกที่ทรงพลัง ยืดหยุ่น และปลอดภัยสำหรับ Provider มีจุดมุ่งหมายเพื่อแก้ไขข้อ จำกัด บางประการของ Provider ในขณะที่เสนอคุณสมบัติเพิ่มเติม เช่น:
- ปรับปรุงความปลอดภัยเวลาคอมไพล์
- ไม่จำเป็นต้อง
BuildContext
เข้าถึง Provider - Provider ที่ไม่เปลี่ยนรูปแบบ
หากต้องการใช้ Riverpod ใน Flutter ให้ทำตามขั้นตอนเหล่านี้:
- เพิ่มแพ็คเกจ ‘flutter_riverpod’ ลงใน
pubspec.yaml
ไฟล์ ของคุณ - สร้าง Provider เพื่อจัดการสถานะแอพของคุณ
- กำหนดตรรกะสำหรับการแก้ไขและปรับปรุงสถานะ
- ล้อมแผนผังวิดเจ็ตของคุณในไฟล์
ProviderScope
. - เข้าถึงและแก้ไขสถานะโดยใช้
ref.watch()
,ref.read()
,ref.listen()
ตัวอย่าง: การใช้แอพยากรณ์อากาศโดยใช้ Riverpod
ในตัวอย่างนี้ เราจะทำแอพสภาพอากาศอย่างง่ายโดยใช้ Riverpod เป็นโซลูชันการจัดการสถานะ แอพจะอนุญาตให้ผู้ใช้ป้อนชื่อเมืองและดึงข้อมูลสภาพอากาศจาก REST API
- เพิ่ม dependencies: เพิ่ม dependencies ต่อไปนี้ใน
pubspec.yaml
ไฟล์ของคุณ:
dependencies:
flutter:
sdk: flutter
http: ^0.13.3
flutter_riverpod: ^1.0.0
- สร้างแบบจำลองสำหรับข้อมูลสภาพอากาศ: สร้าง
weather.dart
ไฟล์และกำหนดWeather
คลาสเพื่อแสดงข้อมูลสภาพอากาศ:
class Weather {
final String cityName;
final double temperature;
Weather({required this.cityName, required this.temperature});
factory Weather.fromJson(Map<String, dynamic> json) {
return Weather(
cityName: json['name'],
temperature: json['main']['temp'],
);
}
}
- สร้างคลาส WeatherRepository เพื่อดึงข้อมูลสภาพอากาศ: สร้าง
weather_repository.dart
ไฟล์และกำหนดWeatherRepository
คลาส:
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'weather.dart';
class WeatherRepository {
Future<Weather> fetchWeather(String cityName) async {
final response = await http.get(Uri.parse(
'https://api.openweathermap.org/data/2.5/weather?q=$cityName&appid=YOUR_API_KEY&units=metric'));
if (response.statusCode == 200) {
return Weather.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to load weather data');
}
}
}
แทนที่ YOUR_API_KEY
ด้วยคีย์ OpenWeatherMap API ของคุณ
- สร้างผู้ให้บริการ Riverpod: ใน
main.dart
ไฟล์ของคุณ ให้สร้าง aFutureProvider
เพื่อจัดการสถานะของข้อมูลสภาพอากาศ:
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'weather_repository.dart';
final weatherProvider = FutureProvider.family<Weather, String>((ref, cityName) async {
final weatherRepository = WeatherRepository();
return await weatherRepository.fetchWeather(cityName);
});
- สร้าง UI: อัปเดต
main.dart
ไฟล์เพื่อสร้าง UI สำหรับการทำแอพสภาพอากาศ:
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
runApp(ProviderScope(child: WeatherApp()));
}
class WeatherApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Riverpod Weather App')),
body: Center(child: WeatherInput()),
),
);
}
}
class WeatherInput extends StatefulWidget {
@override
_WeatherInputState createState() => _WeatherInputState();
}
class _WeatherInputState extends State<WeatherInput> {
TextEditingController _cityNameController = TextEditingController();
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: _cityNameController,
decoration: InputDecoration(labelText: 'City Name'),
),
ElevatedButton(
onPressed: () => context.refresh(weatherProvider(_cityNameController.text)),
child: Text('Get Weather'),
),
Consumer(builder: (context, watch, _) {
final weatherAsyncValue = watch(weatherProvider(_cityNameController.text));
return weatherAsyncValue.map(
data: (_) => Text(''),
loading: (_) => CircularProgressIndicator(),
error: (err) => Text(err.error.toString()),
);
}),
],
);
}
}
ในตัวอย่างนี้ เราทำแอพสภาพอากาศอย่างง่ายโดยใช้ Riverpod เป็นโซลูชั่นการจัดการของรัฐ แอพนี้อนุญาตให้ผู้ใช้ป้อนชื่อเมืองและดึงข้อมูลสภาพอากาศจาก REST API โดยใช้WeatherRepository
คลาส สถานะของข้อมูลสภาพอากาศได้รับการจัดการโดยการFutureProvider
โทร weatherProvider
UI สร้างขึ้นโดยใช้StatefulWidget
การเรียกWeatherInput
ซึ่งรวมถึง a TextField
สำหรับผู้ใช้อินพุตและ an ElevatedButton
เพื่อทริกเกอร์การดึงข้อมูล วิดConsumer
เจ็ตจะรับฟังการเปลี่ยนแปลงในweatherProvider
และอัปเดต UI ตามลำดับ โดยแสดงตัวบ่งชี้ความคืบหน้าขณะโหลดและข้อมูลที่ดึงมาหรือข้อความแสดงข้อผิดพลาดหากมีปัญหาใดๆ เกิดขึ้น
การจัดการสถานะเป็นทักษะที่จำเป็นสำหรับนักพัฒนา Flutter ทุกคน เมื่อทำความเข้าใจและเลือกเทคนิคที่เหมาะสมสำหรับการทำแอพของคุณ คุณจะมั่นใจได้ถึงการจัดการข้อมูลที่มีประสิทธิภาพและประสบการณ์การใช้งานที่ราบรื่น Provider, Bloc/Cubit, Redux และ Riverpod เป็นตัวเลือกยอดนิยม โดยแต่ละตัวเลือกมีจุดเด่นและรูปแบบการใช้งานที่แตกต่างกัน เลือกสิ่งที่เหมาะสมกับความต้องการและความซับซ้อนของการทำแอพ Flutter ของคุณมากที่สุด