데이터를 Bloc에 전부 몰아 놓고 stream을 통해 해당 데이터가 변화할 때마다 UI를 업데이트하는 디자인 패턴이다.
특정 라이브러리, 패키지가 아니기 때문에 어느 프레임워크, 언어에서나 React에서도 RxJS를 활용해서 Bloc 패턴을 사용할 수 있다.
bloc패턴은 비즈니스 로직과 UI를 분리한다. bloc에 상태와 관련된 데이터들이 모여있으며 화면은 데이터 관련 처리를 하지 않고 단순히 bloc에서 데이터를 받아 화면에 출력합니다.
Bloc에 일괄적으로 데이터를 모아 처리한다는 점에서는 상태 관리 Redux와 비슷하며
값이 변하는 것을 감지(구독)해서 새로 렌더한다는 점에선 Reactive programming과 닿아있습니다.
데이터를 담당하는 코드와 UI를 담당하는 코드가 분리되면서 좀 더 깔끔하게 코딩할 수도 있고, 데이터를 중앙 집권적으로 처리하기도 쉬워집니다.
직접 활용해봅시다
버튼을 누를 때마다 1씩 카운터를 증가시키는 앱을 작성한다고 했을 때 곧바로 생각할 수 있는 작성법은
1. stful 위젯 내 count 변수 선언
2. 버튼을 누를 때 마다 setState를 통해 count++
3. UI에 반영
일 터입니다.
그러나 Bloc 패턴으로 구현해보면 다음과 같이 됩니다.
1. count 변수와 해당 변수를 변화 시키는 로직을 bloc에 작성합니다.
2. 해당 값을 구독할 수 있도록 stream을 설계합니다.
3. 해당 bloc을 불러와 UI를 담당하는 부분에서 렌더합니다.
bloc을 정의합니다.
rxdart를 이용해서 stream을 만들 수 있습니다.
import 'package:rxdart/rxdart.dart';
class CounteBlock {
int count = 0;
// seeded를 통해 초기값을 0으로 설정함
// rxdart를 이용함
final countSubject = BehaviorSubject<int>.seeded(0);
void addCounter() {
count++;
// add를 통해 count를 구독하도록 만듦
countSubject.add(count);
}
// getter를 설정해서 내부 변수를 외부에서 사용할 수 있도록 조치
Stream<int> get count$ => countSubject.stream;
}
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:rxdart/rxdart.dart';
// 정의한 bloc을 import합니다.
import 'bloc/counter_block.dart';
// bloc입니다.
final counterBloc = CounteBlock();
main() {
runApp(MaterialApp(
title: "counter",
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Home(),
));
}
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("bloc")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// block에서 정의한 변수를 사용하기 위해 StreamBuilder를 사용합니다.
StreamBuilder(
// 사용할 stream은 앞서 bloc에서 정의한 바가 있습니다.
stream: counterBloc.count$,
builder: (context, snapshot) {
if (snapshot.hasData) {
// snapshot.data에는 데이터가 들어있습니다.
return Text("count : ${snapshot.data}");
} else {
return CircularProgressIndicator();
}
}),
RaisedButton(
onPressed: () {
// 버튼을 누를 때마다 bloc에서 정의한 addCounter 메서드를 사용합니다.
counterBloc.addCounter();
},
child: Text("ADD"))
],
),
));
}
}
'📱 Mobile > 📱 (old) Flutter v 1.0' 카테고리의 다른 글
Sliver (0) | 2020.07.07 |
---|---|
network image 캐싱하기 (0) | 2020.07.06 |
stream, StreamBuilder (0) | 2020.07.05 |
flutter 테스트 하기 (0) | 2020.07.05 |
Android app 빌드 및 플레이 스토어 배포 과정 (0) | 2020.05.26 |