+8

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 Bloc tên là CounterBloc kế 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ượng CounterBloc cho toàn bộ ứng dụng.
  • Trong build của MyApp, sử dụng BlocBuilder để lắng nghe sự thay đổi của CounterBloc và cập nhật giao diện.
  • Khi nhấn nút FloatingActionButton, gọi phương thức add của CounterBloc với sự kiện IncrementEvent để 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 CounterProvider kế thừa từ ChangeNotifier để quản lý trạng thái đếm số.
  • Sử dụng ChangeNotifierProvider để cung cấp đối tượng CounterProvider cho toàn bộ ứng dụng.
  • Trong build của MyApp, sử dụng Consumer để lắng nghe sự thay đổi của CounterProvider và cập nhật giao diện.
  • Khi nhấn nút FloatingActionButton, gọi phương thức increment của CounterProvider để tăng biến đếm và thông báo cho Consumer cậ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 CounterController kế 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ượng CounterController cho toàn bộ ứng dụng.
  • Trong build của MyApp, sử dụng Obx để lắng nghe sự thay đổi của biến _count và cập nhật giao diện.
  • Khi nhấn nút FloatingActionButton, gọi phương thức increment của CounterController để 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

GetX: https://pub.dev/packages/get


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí