Bloc, Provider, GetX. Đâu là thư viện quản lí state Flutter tốt nhất?
Mở đầu
Khi nói đến quản lý state trong Flutter, có một số lựa chọn phổ biến như Bloc, Provider, GetX, và các thư viện khác. Mỗi thư viện đều có những ưu và nhược điểm riêng. Vậy đâu mới là sự lựa chọn tối ưu cho dự án? Dưới đây là một phân tích về các thư viện này. Mọi người có đóng góp gì hãy để lại bình luận bên dưới nha.

Ưu, nhược điểm và demo cho từng thư viện
1. Bloc (Business Logic Component):
- Bloc là một mô hình kiến trúc được thiết kế để phân tách logic nghiệp vụ khỏi giao diện người dùng.
- Nó sử dụng các Streams và Sinks để truyền dữ liệu giữa các thành phần khác nhau.
- Bloc thường được sử dụng cùng với các thư viện hỗ trợ như RxDart hoặc flutter_bloc.
- Ưu điểm: Mô hình rõ ràng, dễ kiểm thử, dễ mở rộng, và tách biệt logic nghiệp vụ khỏi giao diện người dùng.
- Nhược điểm: Cấu trúc phức tạp hơn, và có thể gây ra lãng phí bộ nhớ nếu không quản lý đúng cách, sẽ khó học cho người mới bắt đầu hay dùng cho các dự án nhỏ.
Demo:
Ví dụ sử dụng thư viện flutter_bloc để quản lý trạng thái đếm số.
// counter_event.dart
abstract class CounterEvent {}
class IncrementEvent extends CounterEvent {}
// counter_bloc.dart
import 'package:bloc/bloc.dart';
import 'counter_event.dart';
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0);
Stream<int> mapEventToState(CounterEvent event) async* {
if (event is IncrementEvent) {
yield state + 1;
}
}
}
// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'counter_bloc.dart';
import 'counter_event.dart';
void main() {
runApp(
BlocProvider(
create: (_) => CounterBloc(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Bloc Demo')),
body: Center(
child: BlocBuilder<CounterBloc, int>(
builder: (context, count) {
return Text(
'$count',
style: TextStyle(fontSize: 24),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
context.read<CounterBloc>().add(IncrementEvent());
},
child: Icon(Icons.add),
),
),
);
}
}
Phân tích:
- Tạo một lớp
CounterEventđể đại diện cho sự kiện tăng biến đếm. - Tạo một
Bloctên làCounterBlockế thừa từBloc<CounterEvent, int>để xử lý sự kiện và quản lý trạng thái đếm số. - Sử dụng
BlocProviderđể cung cấp đối tượngCounterBloccho toàn bộ ứng dụng. - Trong
buildcủaMyApp, sử dụngBlocBuilderđể lắng nghe sự thay đổi củaCounterBlocvà cập nhật giao diện. - Khi nhấn nút
FloatingActionButton, gọi phương thứcaddcủaCounterBlocvới sự kiệnIncrementEventđể tăng biến đếm và cập nhật giao diện.
2. Provider:
- Provider là một thư viện quản lý state đơn giản và nhỏ gọn.
- Nó sử dụng mô hình InheritedWidget để truyền data xuống cây widget.
- Provider cung cấp các lớp như ChangeNotifierProvider, StreamProvider, và FutureProvider để quản lý các loại state khác nhau.
- Ưu điểm: Dễ học, dễ sử dụng, và đơn giản hóa việc quản lý state.
- Nhược điểm: Có thể gây ra vấn đề hiệu suất nếu sử dụng quá nhiều provider, và không có cấu trúc rõ ràng cho logic nghiệp vụ.
Demo:
Ví dụ này sử dụng ChangeNotifierProvider để quản lý trạng thái của một đối tượng đếm số.
// counter_provider.dart
import 'package:flutter/material.dart';
class CounterProvider extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
// main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'counter_provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (_) => CounterProvider(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Provider Demo')),
body: Center(
child: Consumer<CounterProvider>(
builder: (context, counterProvider, child) {
return Text(
'${counterProvider.count}',
style: TextStyle(fontSize: 24),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
context.read<CounterProvider>().increment();
},
child: Icon(Icons.add),
),
),
);
}
}
Phân tích:
- Tạo một lớp
CounterProviderkế thừa từChangeNotifierđể quản lý trạng thái đếm số. - Sử dụng
ChangeNotifierProviderđể cung cấp đối tượngCounterProvidercho toàn bộ ứng dụng. - Trong
buildcủaMyApp, sử dụngConsumerđể lắng nghe sự thay đổi củaCounterProvidervà cập nhật giao diện. - Khi nhấn nút
FloatingActionButton, gọi phương thứcincrementcủaCounterProviderđể tăng biến đếm và thông báo choConsumercập nhật giao diện.
3. GetX:
- GetX là một thư viện quản lý state, định tuyến, và thực hiện các tác vụ khác trong Flutter.
- Nó cung cấp các tính năng như quản lý dependencies, quản lý state, định tuyến, và quản lý thủ tục.
- GetX sử dụng reactive programming để quản lý state và cung cấp các lớp như GetBuilder, Obx, và GetX để xây dựng giao diện người dùng.
- Ưu điểm: Tích hợp nhiều tính năng, cú pháp ngắn gọn, và dễ học.
- Nhược điểm: Có thể gây ra vấn đề hiệu suất nếu sử dụng quá nhiều GetBuilder hoặc Obx, và thiếu tính linh hoạt trong một số trường hợp.
Demo:
Ví dụ sử dụng thư viện get để quản lý trạng thái đếm số.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class CounterController extends GetxController {
final _count = 0.obs;
int get count => _count.value;
void increment() {
_count.value++;
}
}
void main() {
runApp(
GetMaterialApp(
home: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
final CounterController controller = Get.put(CounterController());
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('GetX Demo')),
body: Center(
child: Obx(
() => Text(
'${controller.count}',
style: TextStyle(fontSize: 24),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: controller.increment,
child: Icon(Icons.add),
),
);
}
}
Phân tích:
- Tạo một lớp
CounterControllerkế thừa từGetxControllerđể quản lý trạng thái đếm số. - Sử dụng
Get.putđể khởi tạo và cung cấp đối tượngCounterControllercho toàn bộ ứng dụng. - Trong
buildcủaMyApp, sử dụngObxđể lắng nghe sự thay đổi của biến_countvà cập nhật giao diện. - Khi nhấn nút
FloatingActionButton, gọi phương thứcincrementcủaCounterControllerđể tăng biến đếm và cập nhật giao diện.
Phân tích chung cho từng thư viện quản lí state
Sau khi đánh giá các ưu và nhược điểm của các thư viện, mình thấy không có một lựa chọn tuyệt đối tốt nhất cho mọi trường hợp. Sự lựa chọn phụ thuộc vào yêu cầu của dự án, quy mô của ứng dụng, và kinh nghiệm của nhóm phát triển.
-
Provider có thể là lựa chọn tốt nhất vì nó đơn giản và dễ sử dụng. Tuy nhiên, khi dự án lớn lên, việc sử dụng quá nhiều Provider có thể gây ra vấn đề hiệu suất và khó quản lý.
-
Bloc là một lựa chọn tuyệt vời cho các ứng dụng lớn và phức tạp, nơi bạn cần tách biệt logic nghiệp vụ khỏi giao diện người dùng. Mục đích việc tách code business logic ra khỏi UI thay vì code gộp chung cả logic và UI vô cùng 1 file, để sau này tài liệu mới có yêu cầu sửa code business logic hay sửa UI sẽ dễ dàng sửa hơn. Chính vì tách biệt logic và UI nên BLoc rất được tin dùng cho các dự án lớn, cần maintain, có tính scale tốt,... BLoc khá giống mô hình MVVM. Bloc có cấu trúc phức tạp, vì vậy nó có thể không quá phù hợp với các dự án nhỏ hoặc các nhóm phát triển mới bắt đầu với Flutter.
-
GetX là một lựa chọn tuyệt vời nếu bạn đang tìm kiếm một thư viện đa năng, cung cấp nhiều tính năng khác nhau như quản lý state, định tuyến, và quản lý dependencies. Tuy nhiên, GetX có thể gây ra vấn đề hiệu suất nếu sử dụng quá nhiều GetBuilder hoặc Obx, và thiếu tính linh hoạt trong một số trường hợp. GetX hay được khuyên dùng cho các dự án nhỏ và cho người mới bắt đầu tiếp cận với quản lí state trong Flutter.
Kết
Không có một lựa chọn tốt nhất cho mọi trường hợp. Bạn nên cân nhắc yêu cầu của dự án, quy mô của ứng dụng, và kinh nghiệm của nhóm phát triển để lựa chọn thư viện quản lý state phù hợp nhất. Ngoài ra, bạn cũng có thể kết hợp các thư viện khác nhau trong cùng một dự án để tận dụng những ưu điểm của chúng.
Tham khảo thêm các document của 3 thư viện trên tại:
Bloc: https://bloclibrary.dev/
Provider: https://pub.dev/packages/provider
All rights reserved