Bloc Pattern cơ bản trong Flutter

1. Bloc Pattern là gì

Bloc Pattern là một Pattern :D, mục đích chính của Pattern này là tách code business logic ra khỏi UI thay vì gộp chung logic và UI vào cùng 1 file. Code business logic được tách ra đó được đặt tên là Bloc (Business Logic Component). Bên cạnh đó, nó giúp quản lý state của 1 màn hình tốt hơn vì các state sẽ được quản lý ở Bloc tách biệt với UI. Chính vì thế, mỗi màn hình trong flutter sẽ tạo ra 1 bloc để xử lý logic và quản lý logic của màn hình đó.

Bloc định nghĩa ra các state, các event. Bloc nhận event từ UI, xử lý logic, biến chuyển state và bắn về UI để cập nhật giao diện. Tư tưởng của bloc khá giống với ReactorKit trong Swift.

Trong Bloc, để nhận event input và phát ra state output, chúng ta cần sử dụng tới Stream Controller để triển khai. Input sẽ được thêm vào sink của StreamController và phía UI sẽ sử dụng stream để lắng nghe nhận state mỗi khi có event được add vào sink

2. Ví dụ minh họa

Để hiểu hơn về bloc, chúng ta sẽ làm 1 màn hình đơn giản như sau:

Màn hình bao gồm 1 Text hiển thị số, 2 Button +1 và -1 để tăng hoặc giảm số trên màn hình 1 đơn vị.

Như vậy, có thể dễ dàng nhận thấy có 2 event là tăng và giảm, state chính là giá trị được hiển thị lên màn hình. Tiến hành code thôi nào.

Bước 1: Định nghĩa các event

abstract class CounterEvent {}

class IncrementEvent extends CounterEvent {
  IncrementEvent(this.value);
  final int value;
}

class DecrementEvent extends CounterEvent {
  DecrementEvent(this.value);
  final int value;
}

Như đã phân tích ở trên, event bao gồm tăng và giảm. Chúng ta sẽ tạo ra 2 lớp event là IncrementEvent và DecrementEvent. 2 lớp này đều có giá trị đầu vào là value với ý nghĩa là tăng hoặc giảm bao nhiêu đơn vị. Trong bài toán cụ thể này, value sẽ bằng 1.

Bước 2: Định nghĩa state

class CounterState {
  CounterState({required this.count});
  int count;

  CounterState copyWith({int? count}) {
    return CounterState(count: count ?? this.count);
  }
}

Tạo lớp CounterState để quản lý các state của màn hình. Trong đó, count là state để hiển thị bộ đếm lên màn hình.

Bước 3: Code logic trong Bloc

Tạo 1 file counter_bloc.dart để chứa logic. Như đã giới thiệu ở trên, nhiệm vụ của bloc là nhận event từ UI, xử lý event và cập nhật lại state. UI lắng nghe state để cập nhật giao diện.

class CounterBloc {
  // Khởi tạo state, init giá trị khởi tạo
  var state = CounterState(count: 0);
  
  // Khởi tạo event controller để nhận event từ UI
  final eventController = StreamController<CounterEvent>.broadcast();
  // Khởi tạo state controller để truyền state đến UI
  final stateController = StreamController<CounterState>.broadcast();

  CounterBloc() {
    eventController.stream.listen((event) {
      if (event is IncrementEvent) {
        state = state.copyWith(count: state.count + event.value);
      } else if (event is DecrementEvent) {
        state = state.copyWith(count: state.count - event.value);
      }
      stateController.sink.add(state);
    });
  }

  void dispose() {
    stateController.close();
    eventController.close();
  }
}

Bước 4: Tích hợp bloc vào UI

import 'package:bloc_example/screen/counter/counter_bloc.dart';
import 'package:flutter/material.dart';

class CounterScreen extends StatelessWidget {
  // Khởi tạo bloc
  var bloc = CounterBloc();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Counter"),
        ),
        body: Center(
          // Sử dụng StreamBuilder để lắng nghe thay đổi stream của stateController và update lại UI
          child: StreamBuilder(
              stream: bloc.stateController.stream,
              initialData: bloc.state, // Khởi tạo giá trị mặc định
              builder:
                  (BuildContext context, AsyncSnapshot<CounterState> snapshot) {
                return Text(
                  (snapshot.data?.count ?? 0).toString(),
                  style: const TextStyle(
                    fontSize: 70,
                    fontWeight: FontWeight.bold,
                  ),
                );
              }),
        ),
        floatingActionButton: Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            IconButton(
              onPressed: () {
                // truyền action vào bloc
                bloc.eventController.sink.add(IncrementEvent(1));
              },
              icon: const Icon(
                Icons.plus_one,
                size: 30,
                color: Colors.white,
              ),
              style: const ButtonStyle(
                  backgroundColor: WidgetStatePropertyAll(Colors.blue)),
            ),
            IconButton(
              onPressed: () {
                // truyền action vào bloc
                bloc.eventController.sink.add(DecrementEvent(1));
              },
              icon: const Icon(
                Icons.exposure_minus_1,
                size: 30,
                color: Colors.white,
              ),
              style: const ButtonStyle(
                  backgroundColor: WidgetStatePropertyAll(Colors.blue)),
            ),
          ],
        ));
  }
}

Kết luận

Như vậy, mình đã giới thiệu cơ bản về Bloc Pattern. Để nâng cao hơn về bloc và tăng tốc độ code, các bạn có thể dùng thêm thư viện như flutter_bloc

Nguồn tham khảo:

https://viblo.asia/p/hoc-bloc-pattern-theo-cach-de-hieu-nhat-maGK7JYO5j2

Tôi là một lập trình viên IOS. Code chính là IOS nhưng thỉnnh thoảng vẫn đá sang Android hoặc web. Mặc dù không quá thông thạo nhưng tôi sẽ chia sẻ những kiến thức mà mình đã tìm hiểu, áp dụng qua.

Bài viết liên quan

Sơ đồ workflow migrate và sqlc trong CI/CD pipeline

Database migration an toàn với Golang golang-migrate sqlc Atlas so sánh

Tại sao cần database migration tool trong Golang Khi xây dựng ứng dụng production với Golang, việc quản lý thay đổi schema database là bài toán bắt buộc. Ba công…

Xem thêm

TypeScript 5.5: type inference cải tiến, decorators chuẩn hóa, isolated declarations

Giới thiệu TypeScript 5.5 mang đến những cải tiến đáng kể cho hệ thống kiểu dữ liệu, khiến mã nguồn an toàn hơn và dễ bảo trì hơn. Bài viết…

Xem thêm

So sánh các web framework Python phổ biến

Giới thiệu So sánh các web framework Python phổ biến là một trong những chủ đề nóng nhất trong thời gian qua. Bài viết này sẽ cung cấp một cái…

Xem thêm
0 0 đánh giá
Article Rating
Theo dõi
Thông báo của
guest
12 Comments
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất