Explore all courses in this category.
Explore all courses in this category.
Nguyễn Đình Cường
0 comment
09 Nov, 2026
Ứng dụng Flutter nhỏ có thể sống ổn với setState, nhưng khi nhiều màn hình cùng dùng chung dữ liệu, bạn sẽ cần một cách quản lý state có tổ chức. Bài viết giúp bạn hiểu các lựa chọn phổ biến và biết khi nào nên dùng cái nào.
setState phù hợp với trạng thái cục bộ của một widget, như bật tắt một ô hay đếm số. Vấn đề xuất hiện khi giỏ hàng, thông tin đăng nhập hoặc cài đặt giao diện cần được nhiều màn hình đọc và sửa. Lúc đó bạn phải truyền dữ liệu qua nhiều tầng widget (prop drilling), code rối và dễ lỗi.
Hầu hết thư viện đều làm cùng một việc: đưa state ra khỏi widget, đặt nó ở nơi có thể chia sẻ, và tự động báo cho các widget quan tâm vẽ lại khi dữ liệu đổi. Khác biệt chủ yếu nằm ở cách viết và mức độ cấu trúc.
Provider là giải pháp đơn giản, được nhiều người dùng đầu tiên. Bạn tạo một lớp kế thừa ChangeNotifier chứa dữ liệu và gọi notifyListeners() khi có thay đổi.
class CartModel extends ChangeNotifier {
final List<String> _items = [];
List<String> get items => List.unmodifiable(_items);
void add(String item) {
_items.add(item);
notifyListeners();
}
}
// Cung cấp ở gốc ứng dụng
ChangeNotifierProvider(
create: (_) => CartModel(),
child: const MyApp(),
)
// Đọc trong widget
final cart = context.watch<CartModel>();
Text('Số món: ${cart.items.length}')
Ưu điểm là dễ học, ít code. Nhược điểm là phụ thuộc vào context, và khi dự án lớn thì cần kỷ luật để không dồn mọi thứ vào vài lớp khổng lồ.
Riverpod do cùng tác giả với Provider phát triển, khắc phục nhiều hạn chế: không phụ thuộc vào cây widget để khai báo, kiểm tra lỗi lúc biên dịch tốt hơn, dễ kiểm thử và dễ xử lý dữ liệu bất đồng bộ như kết quả gọi API (loading, data, error). Đổi lại, bạn cần học thêm một số khái niệm như provider, ref và các loại notifier.
Bloc áp dụng mô hình sự kiện và trạng thái: giao diện gửi event, Bloc xử lý và phát ra state mới. Cách này rất rõ ràng và dễ theo dõi, phù hợp với nhóm lớn cần quy ước chặt, nhưng khá nhiều code mẫu so với các lựa chọn khác.
| Bối cảnh | Gợi ý |
|---|---|
| Học và làm ứng dụng nhỏ | setState, sau đó Provider |
| Dự án vừa, nhiều dữ liệu bất đồng bộ | Riverpod |
| Nhóm lớn, cần quy trình chặt chẽ | Bloc hoặc Riverpod |
Không có lựa chọn đúng tuyệt đối. Quan trọng là cả nhóm thống nhất một cách và áp dụng nhất quán.
Đừng sa đà vào việc so sánh thư viện quá lâu. Hãy chọn một cái, làm một dự án thật và rút kinh nghiệm. Khi hiểu bản chất, chuyển từ thư viện này sang thư viện khác sẽ không khó.
Điểm mạnh dễ thấy của Riverpod là cách xử lý kết quả gọi API với ba trạng thái rõ ràng. Giả sử bạn có hàm fetchPosts trả về Future:
final postsProvider = FutureProvider<List<Post>>((ref) async {
return fetchPosts();
});
class PostsPage extends ConsumerWidget {
const PostsPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final posts = ref.watch(postsProvider);
return posts.when(
loading: () => const Center(child: CircularProgressIndicator()),
error: (e, st) => Center(child: Text('Lỗi: $e')),
data: (items) => ListView(
children: [for (final p in items) ListTile(title: Text(p.title))],
),
);
}
}
Phương thức when buộc bạn xử lý đủ cả ba trường hợp, nên khó quên màn hình lỗi hay màn hình chờ. Để làm mới dữ liệu, gọi ref.invalidate(postsProvider). Cách làm này thay cho đoạn FutureBuilder thủ công và đặt logic tải dữ liệu ra khỏi widget, giúp kiểm thử dễ hơn rất nhiều.
Bạn không cần chọn đúng thư viện ngay ngày đầu rồi viết lại tất cả. Một lộ trình êm ái là: bắt đầu bằng setState cho trạng thái cục bộ, khi thấy dữ liệu cần chia sẻ thì chuyển các phần đó sang Provider hoặc Riverpod, còn phần cục bộ vẫn để nguyên. Hai cách sống chung hoàn toàn bình thường trong cùng một ứng dụng.
Khi đã dùng một thư viện, hãy tập thói quen tách mô hình dữ liệu bất biến (immutable): thay vì sửa trực tiếp danh sách, tạo bản sao mới với thay đổi. Điều này giúp thư viện phát hiện thay đổi chính xác và tránh lỗi giao diện không cập nhật. Cuối cùng, viết thử bài kiểm thử cho lớp quản lý state; đó là phép thử xem thiết kế của bạn đã tách khỏi giao diện đủ tốt hay chưa.
Nếu bạn cần lộ trình có hướng dẫn cho phần kiến trúc ứng dụng Flutter, hãy ghé qua các khóa học trên codebem.com để xem nội dung phù hợp.
Nguyễn Đình Cường
0 comment