Flutter BLOC – Apakah kamu seorang mobile developer? Kalau iya, harusnya kamu sudah tidak asing lagi dengan salah satu framework yang cukup populer yang dapat mengembangkan aplikasi multi platform dalam satu basis kode saja. Teknologi framework tersebut adalah Flutter.
Flutter merupakan framework aplikasi mobile yang bersifat hybrid dan dikembangkan langsung oleh Google. Dalam Flutter seluruh komponen merupakan widget yang terdiri dari 2 jenis, yaitu Stateful dan Stateless. Untuk mengelola widget tersebut, kamu harus memahami tentang apa itu state, dan bagaimana cara mengelola sebuah state agar aplikasi dapat berjalan dengan efektif.
State itu sendiri merupakan sebuah data yang dibutuhkan untuk membangun tampilan UI aplikasi setiap saat. State ini lah yang menjadi trigger untuk me-redraw tampilan user interface. Ketika terjadi perubahan, UI akan me-rebuild secara otomatis dari awal.
Untuk mengelola sebuah state, terdapat package yang sangat direkomendasikan oleh Google yaitu Flutter BLOC, atau kepanjangan dari Business Logic Component. Package ini akan mempermudah kamu dalam proses pengelolaan state aplikasi menjadi lebih terstruktur. Pada artikel kali ini, kita akan mengulik lebih jauh tentang apa itu BLOC dan bagaimana cara menggunakannya.
Apa itu Flutter BLOC?
Flutter BLOC adalah state management system pada Flutter yang dibuat dan dikembangkan oleh Felix Angelov. BLOC pattern membantu pengelolaan state dan membuat akses ke data tersentralisasi.
Seperti namanya, BLOC menggunakan pendekatan arsitektur business logic dan persentation (view) yang dibuat secara terpisah. Tujuan dari BLOC sendiri adalah membuat kode program aplikasi kamu menjadi lebih mudah dibaca, terstruktur, maintainable, dan testable.
Ketika membangun atau membuat aplikasi dalam production-ready, manajemen pengelolaan state menjadi sangat penting. Oleh karena itu, architectural pattern atau structured project / codebase diperlukan. BLOC menggunakan pendekatan STREAMS atau REACTIVE. Secara umum, data akan bergerak dari BLOC ke UI, atau dari UI ke BLOC, dalam bentuk streams.
Kamu dapat melihat dokumentasi tentang package Bloc lebih lengkap di Bloclibrary.
Fitur utama yang menjadi core concept dalam package BLOC ada 2, yaitu:
- BLOC itu sendiri, dan
- CUBIT
Kedua fitur diatas memiliki kegunaan masing-masing yang dapat digunakan sesuai kondisi dan kebutuhan. Cubit dinilai memiliki fungsi untuk mengelola state yang lebih sederhana dibanding BLOC.
Karena, di dalam Cubit hanya ada interaksi antara business logic dan state saja, tanpa ada event spesifik yang didefinisikan. Berbeda dengan BLOC yang memiliki struktur lengkap mulai dari business logic, event, dan state.
CUBIT
Cubit adalah class yang dapat kamu gunakan di dalam library bloc yang extends dengan Blocbase dan dapat kamu gunakan untuk mengelola jenis state apapun.
Bloc jenis Cubit akan mengekpos function yang dapat dipanggil sebagai trigger perubahan dalam state.
Cara kerja dari Cubit adalah bloc yang menggunakan konsep function-state. Bisa dikatakan konsep Cubit lebih sederhana dan mudah dipahami ketimbang konsep bloc.
Cara Menggunakan Cubit
Ketika kamu ingin membuat sebuat Cubit, kamu harus mendefinisikan terlebih dahulu type data dari state yang akan di kelola. Kamu dapat mengelola data berupa variabel primitif maupun custom class jika diperlukan.
Pada contoh yang akan kita bahas kali ini, kita hanya menggunakan data sederhana yaitu berupa variabel integer saja.
Langkah pertama adalah buat file yang extends dengan class Cubit, kemudian beri nama file tersebut dengan counter_cubit.dart.
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
}
Seperti yang bisa kamu lihat di atas, kita menginisialisasi nilai state didalam cubit berupa integer dengan nilai 0. Artinya, kita dapat menggunakan data state tersebut di widget manapun yang membutuhkan data pada CounterCubit.
Selanjutnya, untuk melakukan perubahan atau update pada data state, kamu dapat menambahkan fungsi increment(), sehingga kode menjadi seperti dibawah:
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
}
Apabila kamu ingin menggunakan data pada cubit didalam widget lain, jangan lupa daftarkan class CounterCubit yang sudah di buat di BlocProvider. BlocProvider merupakan widget yang biasanya diletakkan paling atas dalam widget tree.
BlocProvider(
create: (_) => CounterCubit(),
child: const CounterView(),
)
Cubit sudah selesai kita buat, selanjutnya bagaimana cara memanggil class CounterCubit dalam file counter_cubit.dart? Pada dasarnya, kamu dapat memanggilnya di class manapun, namun pada contoh kali ini, kita akan memanggilnya di fungsi main().
void main() {
final cubit = CounterCubit();
print(cubit.state); // 0
cubit.increment();
print(cubit.state); // 1
cubit.close();
}
import dan lakukan instansiasi pada class CounterCubit didalam fungsi main. Selanjutnya kamu dapat memanggil fungsi increment() untuk mengupdate nilai dari data (state) pada CounterCubit.
BLOC
Bloc adalah class yang lebih lengkap ditambah dengan adanya class events untuk mentrigger perubahan pada state, tidak seperti Cubit yang menggunakan function.
Bloc dan Cubit keduanya extends dengan BlocBase yang memiliki kesamaan dalam hal public API.
Dibandingkan memanggil sebuah function didalam bloc dan langsung mengeksekusi state baru, Bloc lebih terstruktur dengan menerima events, dan merubah event tersebut menjadi state sebagai output.
Cara Menggunakan BLOC
Sebenarnya, cara menggunakan Bloc mirip dengan membuat sebuah Cubit. Perbedaannya terletak pada bagaimana cara kita mengelola state menggunakan event.
Events merupakan masukkan (input) pada Bloc. Events biasanya dieksekusi ketika adanya interaksi pengguna seperti menekan tombol.
Langkah pertama adalah buat sebuah file yang extends dengan Bloc, diikuti dengan class event dan state yang ingin dikelola, dalam hal ini sama halnya dengan cubit, kita hanya menggunakan variabel integer saja.
Beri file tersebut dengan nama counter_bloc.dart.
abstract class CounterEvent {}
class CounterIncrementPressed extends CounterEvent {}
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0) {
on<CounterIncrementPressed>((event, emit) {
// handle incoming `CounterIncrementPressed` event
})
}
}
Class events kita buat menjadi abstract class, agar events yang kita buat memiliki contract atau seragam, berfungsi sebagai pembeda dengan class events pada bloc lain.
Selanjutnya, untuk melakukan perubahan atau update pada data state, kamu dapat menambahkan fungsi emit yang berisi penambahan nilai pada state.
abstract class CounterEvent {}
class CounterIncrementPressed extends CounterEvent {}
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0) {
on<CounterIncrementPressed>((event, emit) {
emit(state + 1);
});
}
}
Bloc sudah berhasil kita buat, selanjutnya kamu dapat melakukan instansiasi class Bloc yang sudah dibuat didalam widget lain secara langsung. Pada contoh kali ini, kita akan coba memanggilnya di function main.
Future<void> main() async {
final bloc = CounterBloc();
print(bloc.state); // 0
bloc.add(CounterIncrementPressed());
await Future.delayed(Duration.zero);
print(bloc.state); // 1
await bloc.close();
}