Skip to main content

2 posts tagged with "Riverpod"

View All Tags

5 Phương pháp quản lý state phổ biến trong Flutter

· 8 min read

Flutter State Management

Giới thiệu

Quản lý state là một trong những khía cạnh quan trọng nhất khi phát triển ứng dụng Flutter. Việc chọn đúng phương pháp quản lý state sẽ giúp code của bạn dễ bảo trì, mở rộng và hiệu quả hơn. Trong bài viết này, chúng ta sẽ khám phá 5 phương pháp quản lý state phổ biến nhất trong Flutter: Provider, Riverpod, Bloc, GetX, và MobX.

1. Provider

Tổng quan

Provider là giải pháp quản lý state được Google khuyến nghị và được xây dựng dựa trên InheritedWidget. Nó cung cấp một cách đơn giản và hiệu quả để quản lý state trong ứng dụng Flutter.

Đặc điểm

  • Đơn giản và dễ học: Syntax rõ ràng, dễ hiểu
  • Được Google khuyến nghị: Chính thức được Flutter team hỗ trợ
  • Hiệu suất tốt: Chỉ rebuild các widget cần thiết
  • Tích hợp tốt với Flutter: Sử dụng các widget có sẵn
  • Không cần code generation: Không cần build_runner

Khi nào sử dụng

  • Ứng dụng nhỏ đến trung bình
  • Team mới bắt đầu với Flutter
  • Cần giải pháp đơn giản, ít boilerplate
  • Muốn tuân theo best practices của Flutter

Ví dụ cơ bản

// Counter Provider
class CounterProvider extends ChangeNotifier {
int _count = 0;
int get count => _count;

void increment() {
_count++;
notifyListeners();
}
}

// Sử dụng
Consumer<CounterProvider>(
builder: (context, counter, child) {
return Text('Count: ${counter.count}');
},
)

Ưu điểm

  • Dễ học và sử dụng
  • Tài liệu phong phú
  • Cộng đồng lớn
  • Phù hợp với hầu hết các use case

Nhược điểm

  • Có thể phức tạp với ứng dụng lớn
  • Cần quản lý lifecycle thủ công
  • Không có compile-time safety mạnh

2. Riverpod

Tổng quan

Riverpod là phiên bản cải tiến của Provider, được tạo ra bởi cùng một tác giả. Nó giải quyết nhiều vấn đề của Provider và cung cấp compile-time safety tốt hơn.

Đặc điểm

  • Compile-time safety: Phát hiện lỗi tại compile time
  • Không cần BuildContext: Có thể truy cập providers từ bất kỳ đâu
  • Testable: Dễ dàng test và mock
  • Provider dependencies: Quản lý dependencies tự động
  • Code generation: Hỗ trợ code generation (optional)

Khi nào sử dụng

  • Ứng dụng lớn, phức tạp
  • Cần type safety cao
  • Muốn test dễ dàng
  • Cần quản lý dependencies tốt hơn

Ví dụ cơ bản

// Counter Provider
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
return CounterNotifier();
});

class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);

void increment() => state++;
}

// Sử dụng
Consumer(
builder: (context, ref, child) {
final count = ref.watch(counterProvider);
return Text('Count: $count');
},
)

Ưu điểm

  • Type-safe hơn Provider
  • Không cần BuildContext
  • Dễ test
  • Quản lý dependencies tốt
  • Hỗ trợ code generation

Nhược điểm

  • Learning curve cao hơn Provider
  • Syntax phức tạp hơn một chút
  • Cộng đồng nhỏ hơn Provider

3. Bloc

Tổng quan

Bloc (Business Logic Component) là một pattern quản lý state dựa trên các khái niệm từ ReactiveX. Nó tách biệt business logic khỏi UI và sử dụng streams để quản lý state.

Đặc điểm

  • Separation of concerns: Tách biệt logic và UI rõ ràng
  • Predictable: State changes có thể dự đoán được
  • Testable: Dễ test business logic
  • Reactive: Sử dụng streams và reactive programming
  • Time-travel debugging: Hỗ trợ debugging tốt

Khi nào sử dụng

  • Ứng dụng lớn, phức tạp
  • Cần quản lý business logic phức tạp
  • Team có kinh nghiệm với reactive programming
  • Cần test coverage cao

Ví dụ cơ bản

// Events
abstract class CounterEvent {}
class IncrementEvent extends CounterEvent {}

// Bloc
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0) {
on<IncrementEvent>((event, emit) => emit(state + 1));
}
}

// Sử dụng
BlocBuilder<CounterBloc, int>(
builder: (context, count) {
return Text('Count: $count');
},
)

Ưu điểm

  • Architecture rõ ràng
  • Dễ test business logic
  • Hỗ trợ time-travel debugging
  • Phù hợp với ứng dụng lớn

Nhược điểm

  • Boilerplate code nhiều
  • Learning curve cao
  • Có thể overkill cho ứng dụng nhỏ

4. GetX

Tổng quan

GetX là một giải pháp all-in-one cho Flutter, không chỉ quản lý state mà còn cung cấp routing, dependency injection, và nhiều tính năng khác.

Đặc điểm

  • All-in-one: State management + Routing + DI
  • Hiệu suất cao: Tối ưu rebuild
  • Syntax đơn giản: Code ngắn gọn
  • Không cần BuildContext: Truy cập từ bất kỳ đâu
  • Tích hợp nhiều tính năng: Navigation, dialogs, snackbars

Khi nào sử dụng

  • Muốn giải pháp all-in-one
  • Cần routing đơn giản
  • Ưu tiên code ngắn gọn
  • Ứng dụng nhỏ đến trung bình

Ví dụ cơ bản

// Controller
class CounterController extends GetxController {
var count = 0.obs;

void increment() => count++;
}

// Sử dụng
final controller = Get.put(CounterController());

Obx(() => Text('Count: ${controller.count}'))

Ưu điểm

  • All-in-one solution
  • Code ngắn gọn
  • Hiệu suất tốt
  • Dễ sử dụng

Nhược điểm

  • Không được Flutter team chính thức khuyến nghị
  • Có thể khó maintain với ứng dụng lớn
  • Tight coupling giữa các tính năng

5. MobX

Tổng quan

MobX là một state management library được port từ JavaScript. Nó sử dụng reactive programming và code generation để quản lý state.

Đặc điểm

  • Reactive: Tự động update khi state thay đổi
  • Minimal boilerplate: Ít code lặp lại
  • Observable pattern: Sử dụng observables
  • Code generation: Sử dụng build_runner
  • Familiar: Nếu đã biết MobX từ JS/React

Khi nào sử dụng

  • Đã quen với MobX từ JavaScript/React
  • Cần reactive programming
  • Muốn ít boilerplate
  • Ứng dụng có state phức tạp

Ví dụ cơ bản

// Store
class CounterStore = _CounterStore with _$CounterStore;

abstract class _CounterStore with Store {

int count = 0;


void increment() => count++;
}

// Sử dụng
Observer(
builder: (_) => Text('Count: ${store.count}'),
)

Ưu điểm

  • Reactive và tự động
  • Ít boilerplate
  • Familiar cho dev từ JS background
  • Dễ sử dụng

Nhược điểm

  • Cần code generation
  • Cộng đồng nhỏ hơn
  • Learning curve nếu chưa quen với reactive

So sánh tổng quan

Tiêu chíProviderRiverpodBlocGetXMobX
Độ phổ biến⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Dễ học⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Type Safety⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Boilerplate⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Testability⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Hiệu suất⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Tài liệu⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐

Kết luận và khuyến nghị

Chọn Provider nếu:

  • Bạn mới bắt đầu với Flutter
  • Ứng dụng nhỏ đến trung bình
  • Muốn giải pháp đơn giản, được Google khuyến nghị

Chọn Riverpod nếu:

  • Bạn đã quen với Provider
  • Cần type safety cao
  • Ứng dụng lớn, phức tạp
  • Ưu tiên testability

Chọn Bloc nếu:

  • Ứng dụng lớn, phức tạp
  • Cần separation of concerns rõ ràng
  • Team có kinh nghiệm với reactive programming
  • Cần test coverage cao

Chọn GetX nếu:

  • Muốn giải pháp all-in-one
  • Ưu tiên code ngắn gọn
  • Ứng dụng nhỏ đến trung bình
  • Cần routing đơn giản

Chọn MobX nếu:

  • Đã quen với MobX từ JavaScript
  • Cần reactive programming
  • Muốn ít boilerplate
  • State phức tạp

Lời khuyên cuối cùng

  1. Bắt đầu đơn giản: Nếu mới bắt đầu, hãy thử Provider trước
  2. Xem xét dự án: Chọn phương pháp phù hợp với quy mô và độ phức tạp
  3. Team experience: Xem xét kinh nghiệm của team
  4. Long-term: Nghĩ về khả năng maintain và scale
  5. Thử nghiệm: Có thể thử nhiều phương pháp để tìm ra cái phù hợp nhất

Quản lý state là một phần quan trọng của Flutter development. Chọn đúng phương pháp sẽ giúp bạn xây dựng ứng dụng tốt hơn!

Provider vs Riverpod: Cái nào tốt hơn trong năm 2025?

· 8 min read

Provider vs Riverpod

Giới thiệu

Provider và Riverpod là hai giải pháp quản lý state phổ biến nhất trong Flutter. Cả hai đều được tạo ra bởi Remi Rousselet, nhưng Riverpod được thiết kế để giải quyết các vấn đề của Provider. Trong năm 2025, cái nào tốt hơn? Hãy cùng phân tích chi tiết.

Provider: Giải pháp được Google khuyến nghị

Ưu điểm

1. Đơn giản và dễ học

Provider có syntax đơn giản, dễ hiểu cho người mới bắt đầu:

// Provider - Đơn giản
class CounterProvider extends ChangeNotifier {
int _count = 0;
int get count => _count;

void increment() {
_count++;
notifyListeners();
}
}

// Sử dụng
Consumer<CounterProvider>(
builder: (context, provider, child) {
return Text('${provider.count}');
},
)

2. Được Google chính thức khuyến nghị

  • Có trong Flutter documentation chính thức
  • Được Flutter team hỗ trợ
  • Tài liệu phong phú và cộng đồng lớn

3. Không cần code generation

  • Không cần build_runner
  • Setup nhanh chóng
  • Ít dependencies

4. Tích hợp tốt với Flutter

  • Sử dụng InheritedWidget
  • Tận dụng widget tree của Flutter
  • Hiệu suất tốt với rebuild tối ưu

Nhược điểm

1. Cần BuildContext

// Phải có BuildContext
final provider = Provider.of<CounterProvider>(context);
// hoặc
context.read<CounterProvider>()

2. Runtime errors

Một số lỗi chỉ phát hiện được khi runtime:

// Lỗi này chỉ phát hiện khi chạy
final provider = Provider.of<CounterProvider>(context); // Có thể null

3. Quản lý dependencies phức tạp

Khi có nhiều providers phụ thuộc nhau:

// Phức tạp khi có dependencies
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => AuthProvider()),
ChangeNotifierProxyProvider<AuthProvider, UserProvider>(
create: (_) => UserProvider(),
update: (_, auth, previous) => previous ?? UserProvider()..init(auth),
),
],
)

4. Testing phức tạp hơn

Cần setup BuildContext cho testing:

testWidgets('test', (tester) async {
await tester.pumpWidget(
ChangeNotifierProvider(
create: (_) => CounterProvider(),
child: MyWidget(),
),
);
});

Riverpod: Giải pháp thế hệ mới

Ưu điểm

1. Compile-time safety

Riverpod phát hiện lỗi tại compile time:

// Lỗi này sẽ được phát hiện khi compile
final count = ref.watch(counterProvider); // Type-safe

2. Không cần BuildContext

Có thể truy cập providers từ bất kỳ đâu:

// Không cần BuildContext
class MyService {
final ref = ProviderContainer();
void doSomething() {
final count = ref.read(counterProvider);
}
}

3. Quản lý dependencies tự động

Riverpod tự động quản lý dependencies:

// Dependencies được quản lý tự động
final authProvider = Provider((ref) => AuthService());

final userProvider = FutureProvider((ref) async {
final auth = ref.watch(authProvider);
return await fetchUser(auth);
});

4. Testing dễ dàng hơn

Không cần BuildContext để test:

test('counter increments', () {
final container = ProviderContainer();
final notifier = container.read(counterProvider.notifier);
notifier.increment();
expect(container.read(counterProvider), 1);
});

5. Hỗ trợ code generation (optional)

Riverpod 2.0 hỗ trợ code generation để giảm boilerplate:


class Counter extends _$Counter {

int build() => 0;

void increment() => state++;
}

6. Provider types đa dạng

  • Provider: Immutable values
  • StateProvider: Simple state
  • StateNotifierProvider: Complex state
  • FutureProvider: Async values
  • StreamProvider: Stream values

Nhược điểm

1. Learning curve cao hơn

Syntax phức tạp hơn Provider một chút:

// Riverpod - Phức tạp hơn một chút
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
return CounterNotifier();
});

class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
}

2. Cộng đồng nhỏ hơn

  • Ít tài liệu hơn Provider
  • Ít ví dụ và tutorials
  • Cộng đồng đang phát triển

3. Breaking changes

Riverpod đã có nhiều breaking changes giữa các version:

  • Riverpod 1.0 → 2.0 có nhiều thay đổi
  • Cần migration guide khi upgrade

So sánh chi tiết

1. Performance

Tiêu chíProviderRiverpod
Rebuild optimization⭐⭐⭐⭐⭐⭐⭐⭐⭐
Memory usage⭐⭐⭐⭐⭐⭐⭐⭐⭐
Initialization⭐⭐⭐⭐⭐⭐⭐⭐⭐

Kết luận: Riverpod có rebuild optimization tốt hơn một chút nhờ compile-time analysis.

2. Developer Experience

Tiêu chíProviderRiverpod
Ease of learning⭐⭐⭐⭐⭐⭐⭐⭐
Type safety⭐⭐⭐⭐⭐⭐⭐⭐
Debugging⭐⭐⭐⭐⭐⭐⭐⭐⭐
IDE support⭐⭐⭐⭐⭐⭐⭐⭐

Kết luận: Provider dễ học hơn, nhưng Riverpod có type safety và debugging tốt hơn.

3. Code Quality

Provider Example

class CounterProvider extends ChangeNotifier {
int _count = 0;
int get count => _count;

void increment() {
_count++;
notifyListeners();
}
}

// Usage
Consumer<CounterProvider>(
builder: (context, provider, child) {
return Text('${provider.count}');
},
)

Riverpod Example

final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
return CounterNotifier();
});

class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
}

// Usage
Consumer(
builder: (context, ref, child) {
final count = ref.watch(counterProvider);
return Text('$count');
},
)

Kết luận: Riverpod có type safety tốt hơn, nhưng Provider đơn giản hơn.

4. Testing

Provider Testing

testWidgets('test', (tester) async {
await tester.pumpWidget(
ChangeNotifierProvider(
create: (_) => CounterProvider(),
child: MaterialApp(
home: CounterWidget(),
),
),
);

expect(find.text('0'), findsOneWidget);
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
expect(find.text('1'), findsOneWidget);
});

Riverpod Testing

test('counter increments', () {
final container = ProviderContainer();
addTearDown(container.dispose);

final notifier = container.read(counterProvider.notifier);
expect(container.read(counterProvider), 0);

notifier.increment();
expect(container.read(counterProvider), 1);
});

Kết luận: Riverpod dễ test hơn vì không cần BuildContext.

5. Ecosystem và Community

Tiêu chíProviderRiverpod
Documentation⭐⭐⭐⭐⭐⭐⭐⭐⭐
Community size⭐⭐⭐⭐⭐⭐⭐⭐
Stack Overflow answers⭐⭐⭐⭐⭐⭐⭐⭐
Tutorials⭐⭐⭐⭐⭐⭐⭐⭐

Kết luận: Provider có ecosystem lớn hơn và nhiều tài liệu hơn.

Use Cases

Chọn Provider nếu:

  1. Bạn mới bắt đầu với Flutter

    • Syntax đơn giản, dễ học
    • Nhiều tài liệu và ví dụ
  2. Ứng dụng nhỏ đến trung bình

    • Đủ mạnh cho hầu hết use cases
    • Không cần complexity không cần thiết
  3. Team đã quen với Provider

    • Không cần học lại
    • Codebase hiện tại đang dùng Provider
  4. Cần giải pháp được Google khuyến nghị

    • Official support
    • Long-term stability

Chọn Riverpod nếu:

  1. Ứng dụng lớn, phức tạp

    • Cần type safety cao
    • Quản lý dependencies tốt hơn
  2. Ưu tiên compile-time safety

    • Phát hiện lỗi sớm
    • Giảm runtime errors
  3. Cần test coverage cao

    • Dễ test hơn
    • Không cần BuildContext
  4. Muốn giải pháp hiện đại

    • Được thiết kế để giải quyết vấn đề của Provider
    • Active development

Migration từ Provider sang Riverpod

Nếu bạn đang dùng Provider và muốn chuyển sang Riverpod:

Bước 1: Thêm dependencies

dependencies:
flutter_riverpod: ^2.4.9

Bước 2: Convert Provider

Provider:

class CounterProvider extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}

Riverpod:

final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
return CounterNotifier();
});

class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
}

Bước 3: Update Widgets

Provider:

Consumer<CounterProvider>(
builder: (context, provider, child) {
return Text('${provider.count}');
},
)

Riverpod:

Consumer(
builder: (context, ref, child) {
final count = ref.watch(counterProvider);
return Text('$count');
},
)

Xu hướng 2025

Provider

  • ✅ Vẫn được Google khuyến nghị
  • ✅ Stable và mature
  • ✅ Ecosystem lớn
  • ⚠️ Ít cập nhật mới

Riverpod

  • ✅ Active development
  • ✅ Nhiều tính năng mới
  • ✅ Đang phát triển mạnh
  • ✅ Riverpod 2.0 với code generation

Kết luận và Khuyến nghị

Cho người mới bắt đầu

Chọn Provider vì:

  • Dễ học hơn
  • Nhiều tài liệu
  • Cộng đồng lớn
  • Được Google khuyến nghị

Cho dự án mới (2025)

Chọn Riverpod nếu:

  • Ứng dụng lớn, phức tạp
  • Cần type safety cao
  • Team có kinh nghiệm
  • Muốn giải pháp hiện đại

Chọn Provider nếu:

  • Ứng dụng nhỏ đến trung bình
  • Team mới với Flutter
  • Cần giải pháp stable
  • Muốn ecosystem lớn

Cho dự án hiện tại

  • Đang dùng Provider: Tiếp tục dùng nếu đang hoạt động tốt
  • Có vấn đề với Provider: Xem xét migrate sang Riverpod
  • Dự án mới: Nên cân nhắc Riverpod cho long-term

Lời khuyên cuối cùng

  1. Không có câu trả lời đúng duy nhất: Cả hai đều tốt, tùy vào use case
  2. Provider vẫn rất tốt: Không cần migrate nếu đang hoạt động tốt
  3. Riverpod là tương lai: Nếu bắt đầu dự án mới, nên xem xét Riverpod
  4. Thử nghiệm: Có thể thử cả hai để tìm ra cái phù hợp nhất
  5. Team decision: Quyết định dựa trên team experience và project requirements

Cả Provider và Riverpod đều là những giải pháp tuyệt vời. Quan trọng là chọn cái phù hợp với dự án và team của bạn!