내가 주로 사용하는 flutter 의 bloc 를 설명해보려는 글을 쓰려고 한다.
첫 회사에 입사했을때는 flutter가 뭔지.. bloc가 뭔지도 몰랐다..
c# 개발자이다보니 안드로이드나 앱 에 대한 기본적인 지식조차 없이 시작하느라 고생이 많았다.
생명주기를 모르다 보니 진짜 이해하지 못하며 개발했다..
flutter bloc는.. 뭐 어떻게 동작한다느니 설명을 하는것보다 코드를 보는게 개발자들 입장에서 혹은 내 입장에서는 더 이해가 빠르지 않을까?
Flutter bloc를 만드려면 기본적으로
bloc , state , event 가 필요하다.. 나는 그이외에도 repository,repositoryAb,Param 등을 더 붙여서 사용한다.
bloc에서는 전체적인 bloc등을 생성해준다.?
state에서는 각 bloc에 대한 상태등을 정의해 준다.
event에서는 bloc에 추가?생성?할 이벤트를 등록할 수 있게 정의해준다.
repository에서는 bloc에서 생성될 이벤트에 알맞는 로직을 실행할 수 있게끔 로직을 생성해준다.
repositoryAb 에서는 repository에서 Future로 돌아갈만한 함수들을 등록해준다 repository에서는 그 함수들을 override 하여 사용한다.
글로만 보면 누구나 이해하지 못할 거 같다
그래서 소스코드를 첨가하려고 한다.
flutter의 기본적인 코드를 예시로 들려고 한다.
처음 실행하면 나오는 버튼 누르면 1씩 증가하는 기본적인 base코드를 bloc 형태로 꾸며보고자 한다.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
flutter 시작시 나오는 기본적인 내용들 이다.
floatingActionButton을 클릭하면 실행되는 함수는 아래와 같다.
void _incrementCounter() {
setState(() {
_counter++;
});
}
이 내용을 bloc로 변하게 하려고 한다.
기본적으로 bloc를 dependencies 에 등록해야 한다.
part 'sample_event.dart';
import 'package:blocsample/bloc/bloc/resouces/sample_repository.dart';
part 'sample_state.dart';
class SampleBloc extends Bloc<SampleEvent, SampleState> {
SampleBloc(SampleState initialState) : super(initialState);
SampleRepository sampleRepository = SampleRepository();
@override
Stream<SampleState> mapEventToState(SampleEvent event) async* {
if (event is AddEvent) {
yield* _mapAdd(event);
}
}
Stream<SampleState> _mapAdd(AddEvent event) async* {
int result =sampleRepository.addCalc(event.num!, event.addNum!);
yield state.update(num:result);
}
}
bloc에 생성될 코드들이다.
각 event 마다 실행될 코드들이 달라진다.
mapEventToState에서 event마다 실행될 함수들을 나누어 준다.
난 버튼을 누를때마다 값이 변하는 걸 생성하기 위해서 _mapAdd를 생성해주었다.
값을 보면 event에서 값 2개를 뽑아온뒤 addCalc에 값을 넣어준뒤 반환되는 값을
state.update를 통해 넣어주었다.
part of 'sample_bloc.dart';
abstract class SampleEvent {}
class AddEvent extends SampleEvent {
int? addNum;
int? num;
AddEvent({this.addNum,this.num});
}
event 코드이다.
event를 등록할때 넣어줄 값을 먼저 정의해준다
나는 숫자 2개를 넣어줄것이기 때문에 int형 변수를 생성해주었다.
num은 기존의 값이며 addNum은 더해질 값이다.
part of 'sample_bloc.dart';
class SampleState {
int? num;
SampleState({this.num});
factory SampleState.empty() {
return SampleState(num: 0);
}
SampleState update({int? num}) {
return SampleState(num:num);
}
SampleState copyWith({int? num}) {
return SampleState(num:num);
}
}
state이다.
상태를 변환하기 위해 사용했던 부분이다..
num에는 현재 의 숫자값을 넣어줄 부분이다.
copyWith는 값을 복사할 부분이고 (사실 잘 안써봐서..모르겠다 써봐야 하는데 ㅜㅜ 기존의 값을 유지하고 바꾸어줄 값이 있을떄 부분적으로 사용하기는 하지만.. 어떻게 설명해야 할지 잘 몰라서 패스)
update는 state의 상태를 업데이트 해주는 부분이다!
empty는 bloc를 등록할때 사용해주었다..
이게 설명이 맞나 싶지만..
class SampleRepository {
int addCalc(int num1, int num2) {
return num1 + num2;
}
}
bloc에 등록된 이벤트마다 실행될 함수가 작성될 부분이다.
addCalc 함수에서는 인자값을 받아서 더해준뒤 되돌려준다.
여기까지가 bloc의 기초 설정이다.
bloc는 기초적으로 설정해주어얄할게 참 많다.. 하지만 하고나면 그뒤에 사용하기에는 더할나위없이 편한거 같다.
다음 장에서 이제 bloc를 어떻게 적용해야할지 다루어 보도록 하겠다.