What to do?
State 관리
React에서 상태관리를 redux, zustand, recoil과 같은 상태관리 라이브러리를 사용 하듯이,
유사하게 Flutter 프로젝트에서도 Bloc 라이브러리를 적용해보자.
Reference
라이브러리 설치
pubspec.yaml 파일 수정
- 상태관리 라이브러리를 사용하기 위한 라이브러리 설치
dependencies:
...
bloc: ^7.0.0
equatable: ^2.0.2
Usage
메세지의 상태를 정의하는 예시
- State 정의
- MessageState라는 Base State를 정의
- MessageSentSuccess라는 State 정의 - props는 message
abstract class MessageState extends Equatable {
// constructor
const MessageState();
// factory
factory MessageState.sent(Message message) => MessageSentSuccess(message);
// props
@override
List<Object> get props => [];
}
class MessageSentSuccess extends MessageState {
// constructor
final Message message;
const MessageSentSuccess(this.message);
// override getter
@override
List<Object> get props => [message];
}
- Event 정의
- MessageSentEvent라는 이벤트 정의
- props는 message
abstract class MessageEvent extends Equatable {
const MessageEvent();
factory MessageEvent.onMessageSent(Message message) => MessageSentEvent(message);
@override
List<Object> get props => [];
}
class MessageSentEvent extends MessageEvent {
final Message message;
const MessageSentEvent(this.message);
@override
List<Object> get props => [message];
}
- Bloc 정의
- Bloc<MessageEvent, MessageState> : Event와 State를 extend해서 Bloc 클래스를 정의
- overriding : 아래의 class들을 override
- mapEventToState : 분기처리를 통해서 이벤트와 상태를 매핑시켜줌
- 이벤트가 MessageSentEvent인 경우, MessageSentSuccess를 반환
- close
- mapEventToState : 분기처리를 통해서 이벤트와 상태를 매핑시켜줌
class MessageBloc extends Bloc<MessageEvent, MessageState> {
final IMessageService _messageService;
StreamSubscription _subscription;
MessageBloc(this._messageService) : super(MessageState.initial());
@override
Stream<MessageState> mapEventToState(MessageEvent event) async* {
...
/// send
if (event is MessageSentEvent) {
await _messageService.send(event.message);
yield MessageState.sent(event.message);
}
}
@override
Future<void> close() {
_subscription?.cancel();
_messageService.dispose();
return super.close();
}
}
State 정의
- init
- sent
- received
- Message
/state_management/message/message_state.dart
abstract class MessageState extends Equatable {
const MessageState();
factory MessageState.initial() => MessageInitial();
factory MessageState.sent(Message message) => MessageSentSuccess(message);
factory MessageState.received(Message message) =>
MessageReceivedSuccess(message);
@override
List<Object> get props => [];
}
class MessageInitial extends MessageState {}
class MessageSentSuccess extends MessageState {
final Message message;
const MessageSentSuccess(this.message);
@override
List<Object> get props => [message];
}
class MessageReceivedSuccess extends MessageState {
final Message message;
const MessageReceivedSuccess(this.message);
@override
List<Object> get props => [message];
}
- Receipt
/state_management/receipt/receipt_state.dart
abstract class ReceiptState extends Equatable {
const ReceiptState();
factory ReceiptState.initial() => ReceiptInitial();
factory ReceiptState.sent(Receipt receipt) => ReceiptSentSuccess(receipt);
factory ReceiptState.received(Receipt receipt) =>
ReceiptReceivedSuccess(receipt);
@override
List<Object> get props => [];
}
class ReceiptInitial extends ReceiptState {}
class ReceiptSentSuccess extends ReceiptState {
final Receipt receipt;
const ReceiptSentSuccess(this.receipt);
@override
List<Object> get props => [receipt];
}
class ReceiptReceivedSuccess extends ReceiptState {
final Receipt receipt;
const ReceiptReceivedSuccess(this.receipt);
@override
List<Object> get props => [receipt];
}
- TypingNotification
/state_management/typing/typing_state.dart
abstract class TypingNotificationState extends Equatable {
const TypingNotificationState();
factory TypingNotificationState.initial() => TypingNotificationInitial();
factory TypingNotificationState.sent() => TypingNotificationSentSuccess();
factory TypingNotificationState.received(TypingEvent typingEvent) =>
TypingNotificationReceivedSuccess(typingEvent);
@override
List<Object> get props => [];
}
class TypingNotificationInitial extends TypingNotificationState {}
class TypingNotificationSentSuccess extends TypingNotificationState {}
class TypingNotificationReceivedSuccess extends TypingNotificationState {
final TypingEvent typingEvent;
const TypingNotificationReceivedSuccess(this.typingEvent);
@override
List<Object> get props => [typingEvent];
}
Event 정의
- MessageEvent
/state_management/message/message_event.dart
abstract class MessageEvent extends Equatable {
const MessageEvent();
factory MessageEvent.onSubscribed(User user) => SubscribeEvent(user);
factory MessageEvent.onMessageReceived(Message message) =>
MessageReceivedEvent(message);
factory MessageEvent.onMessageSent(Message message) =>
MessageSentEvent(message);
@override
List<Object> get props => [];
}
class SubscribeEvent extends MessageEvent {
final User user;
const SubscribeEvent(this.user);
@override
List<Object> get props => [user];
}
class MessageReceivedEvent extends MessageEvent {
final Message message;
const MessageReceivedEvent(this.message);
@override
List<Object> get props => [message];
}
class MessageSentEvent extends MessageEvent {
final Message message;
const MessageSentEvent(this.message);
@override
List<Object> get props => [message];
}
- ReceiptEvent
/state_management/receipt/receipt_event.dart
abstract class ReceiptEvent extends Equatable {
const ReceiptEvent();
factory ReceiptEvent.onSubscribed(User user) => SubscribeEvent(user);
factory ReceiptEvent.onReceiptSent(Receipt receipt) => ReceiptSentEvent(receipt);
@override
List<Object> get props => [];
}
class SubscribeEvent extends ReceiptEvent {
final User user;
const SubscribeEvent(this.user);
@override
List<Object> get props => [user];
}
class ReceiptReceivedEvent extends ReceiptEvent {
final Receipt receipt;
const ReceiptReceivedEvent(this.receipt);
@override
List<Object> get props => [receipt];
}
class ReceiptSentEvent extends ReceiptEvent {
final Receipt receipt;
const ReceiptSentEvent(this.receipt);
@override
List<Object> get props => [receipt];
}
- TypingNotification
/state_management/typing/typing_event.dart
abstract class TypingNotificationEvent extends Equatable {
const TypingNotificationEvent();
factory TypingNotificationEvent.onSubscribed(User user,
{List<String> userWithChat}) =>
SubscribeEvent(user, userWithChat: userWithChat);
factory TypingNotificationEvent.onTypingNotificationSent(
TypingEvent typing) =>
TypingNotificationSentEvent(typing);
@override
List<Object> get props => [];
}
class SubscribeEvent extends TypingNotificationEvent {
final User user;
final List<String> userWithChat;
const SubscribeEvent(this.user, {this.userWithChat});
@override
List<Object> get props => [user];
}
class NotSubscribeEvent extends TypingNotificationEvent {}
class TypingNotificationReceivedEvent extends TypingNotificationEvent {
final TypingEvent typing;
const TypingNotificationReceivedEvent(this.typing);
@override
List<Object> get props => [typing];
}
class TypingNotificationSentEvent extends TypingNotificationEvent {
final TypingEvent typing;
const TypingNotificationSentEvent(this.typing);
@override
List<Object> get props => [typing];
}
Bloc
- Message
/state_management/message/message_block.dart
class MessageBloc extends Bloc<MessageEvent, MessageState> {
final IMessageService _messageService;
StreamSubscription _subscription;
MessageBloc(this._messageService) : super(MessageState.initial());
@override
Stream<MessageState> mapEventToState(MessageEvent event) async* {
/// subscribe
if (event is SubscribeEvent) {
await _subscription?.cancel();
_subscription = _messageService.messages(user: event.user).listen((msg) {
add(MessageReceivedEvent(msg));
});
}
/// receive
if (event is MessageReceivedEvent) {
yield MessageState.received(event.message);
}
/// send
if (event is MessageSentEvent) {
await _messageService.send(event.message);
yield MessageState.sent(event.message);
}
}
@override
Future<void> close() {
_subscription?.cancel();
_messageService.dispose();
return super.close();
}
}
- Receipt
/state_management/receipt/receipt_bloc.dart
class ReceiptBloc extends Bloc<ReceiptEvent, ReceiptState> {
final IReceiptService _receiptService;
StreamSubscription _subscription;
ReceiptBloc(this._receiptService) : super(ReceiptState.initial());
@override
Stream<ReceiptState> mapEventToState(ReceiptEvent event) async* {
/// subscribe
if (event is SubscribeEvent) {
await _subscription?.cancel();
_subscription = _receiptService
.receipts(event.user)
.listen((receipt) => add(ReceiptReceivedEvent(receipt)));
}
/// received
if (event is ReceiptReceivedEvent) {
yield ReceiptState.received(event.receipt);
}
/// send
if (event is ReceiptSentEvent) {
await _receiptService.send(event.receipt);
yield ReceiptState.sent(event.receipt);
}
}
@override
Future<void> close() {
_subscription?.cancel();
_receiptService.dispose();
return super.close();
}
}
- TypingEvent
/state_management/typing/typing_bloc.dart
class TypingBloc
extends Bloc<TypingNotificationEvent, TypingNotificationState> {
final ITypingNotificationService _typingNotificationService;
StreamSubscription _subscription;
TypingBloc(this._typingNotificationService)
: super(TypingNotificationState.initial());
@override
Stream<TypingNotificationState> mapEventToState(
TypingNotificationEvent event) async* {
/// Subscribe but not user
if (event is SubscribeEvent && event.userWithChat == null) {
add(NotSubscribeEvent());
return;
}
/// Subscribe
if (event is SubscribeEvent) {
await _subscription?.cancel();
_subscription = _typingNotificationService
.subscribe(event.user, event.userWithChat)
.listen((typing) => add(TypingNotificationReceivedEvent(typing)));
}
/// Received
if (event is TypingNotificationReceivedEvent) {
yield TypingNotificationState.received(event.typing);
}
/// Send
if (event is TypingNotificationSentEvent) {
await _typingNotificationService.send(event: event.typing);
yield TypingNotificationState.sent();
}
/// Not Subscribe
if (event is NotSubscribeEvent) {
yield TypingNotificationState.initial();
}
}
@override
Future<void> close() {
_subscription?.cancel();
_typingNotificationService.dispose();
return super.close();
}
}
'Flutter' 카테고리의 다른 글
[Flutter] 채팅앱 만들기 #9 (0) | 2023.03.08 |
---|---|
[Flutter] 채팅앱 만들기 #8 (0) | 2023.03.07 |
[Flutter] 채팅앱 만들기 #6 (0) | 2023.03.05 |
[Flutter] 채팅앱 만들기 #5 (0) | 2023.03.04 |
[Flutter] 채팅앱 만들기 #4 (0) | 2023.03.01 |