이전 글에서 블록 개념 정리를 했으니 이제 실제로 구현해보자.
블록 공식 홈 튜토리얼을 참고했다.
https://bloclibrary.dev/tutorials/flutter-counter/
class CounterPage extends StatelessWidget {
Widget build(BuildContext context) {
// BlocBuilder를 사용하여 상태를 감지하고 UI를 업데이트
return Scaffold(
appBar: AppBar(title: Text('Counter')),
body: Center(
child: BlocBuilder<CounterCubit, int>(
builder: (context, count) {
return Text('$count', style: TextStyle(fontSize: 24));
},
),
),
Cubit 의 상태변화 감지
void main() {
Bloc.observer = CounterObserver(); // 상태 변화를 관찰하도록 설정
runApp(MyApp());
}
flutter pub add flutter_bloc
import 'package:bloc/bloc.dart';
// BlocObserver 생성
class CounterObserver extends BlocObserver {
const CounterObserver();
void onChange(BlocBase bloc, Change change) {
super.onChange(bloc, change);
print('${bloc.runtimeType} $change');
}
}
void main() {
// initializing CounterObserver
Bloc.observer = const CounterObserver();
runApp(const MyApp());
}
이제 페이지를 만들러 떠난다
import 'package:bloc_provider_test/counter_cubit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class CounterPage extends StatelessWidget {
const CounterPage({super.key});
Widget build(BuildContext context) {
// BlocProvider 설정
return BlocProvider(
// 여기서 큐빗 객체 생성
create: (BuildContext context) {
return CounterCubit();
},
child: CounterView(),
);
}
}
상태 관리 비즈니스 로직을 cubit 에 작성한다. increment 메서드를 실행하면 emit 를 통해 현재 상태를 +1 업데이트. 생성자를 통해 상태를 0으로 초기화 하고 있기 때문에 상태의 초기값은 0이 된다.
import 'package:bloc/bloc.dart';
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
// add 1 to the current state.
void increment() => emit(state + 1);
// subtract 1 from the current state.
void decrement() => emit(state - 1);
}
플로팅버튼이 클릭되면 cubit의 메서드를 실행한다. context.read() 를 통해 큐빗에 접근할 수 있는 이유는 아까 상위 위젯에서 BlocProdiver 를 통해 해당 큐빗을 등록해주었기 때문.
import 'package:bloc_provider_test/counter_cubit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class CounterView extends StatelessWidget {
const CounterView({super.key});
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: BlocBuilder<CounterCubit, int>(
builder: (context, state) {
return Text('$state');
}),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => context.read<CounterCubit>().increment(),
),
SizedBox(height: 8),
FloatingActionButton(
child: Icon(Icons.remove),
onPressed: () => context.read<CounterCubit>().decrement(),
)
],
),
);
}
}
이제 메인 페이지를 CounterPage로 변경해주면 끝. 앱이 제대로 작동되는 것을 볼 수 있다.
import 'package:bloc/bloc.dart';
import 'package:bloc_provider_test/counter_observer.dart';
import 'package:bloc_provider_test/counter_page.dart';
import 'package:flutter/material.dart';
void main() {
// initializing CounterObserver
Bloc.observer = const CounterObserver();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: CounterPage()
);
}
}

옵저버가 콘솔에 이런 식으로 상태를 출력해준다.
