๐ฆ ํตํฉ์ด๋ฒคํธ ์์คํ ๊ตฌํ ๋ฐ ์ฌ์ฉ ๊ฐ์ด๋ - devlink-community/gaesubang-app GitHub Wiki
Firebase ์ฐ๋ ์ฑ์์ ํ๋ฉด ๊ฐ ์ํ ์ผ๊ด์ฑ ์ ์ง๋ฅผ ์ํด ํตํฉ ์ด๋ฒคํธ ์์คํ ์ ๊ตฌํํ์ต๋๋ค. ์ด ์์คํ ์ ์ฑ ๋ด ์ค์ ์ด๋ฒคํธ(ํ๋กํ ๋ณ๊ฒฝ, ๊ฒ์๊ธ ์ ๋ฐ์ดํธ, ๋๊ธ ์ถ๊ฐ ๋ฑ)๋ฅผ ๋ฐํ(emit) ํ๊ณ ๊ตฌ๋ (listen) ํ๋ ๋ฐฉ์์ผ๋ก ์๋ํฉ๋๋ค.
๋ฌธ์ | ์์ธ | ํด๊ฒฐ์ฑ |
---|---|---|
๋๊ธ/์ข์์ ๋ฐ์ ์ง์ฐ | ํ๋ฉด ๊ฐ ๋ ๋ฆฝ์ ์ํ ๊ด๋ฆฌ๋ก ์ธํ ๋น๋๊ธฐ ์ ๋ฐ์ดํธ | ์ด๋ฒคํธ ๊ธฐ๋ฐ ์๋ ๊ฐฑ์ ์์คํ ๋์ |
ํ๋กํ ๋ณ๊ฒฝ ๋ฏธ๋ฐ์ | ์ฑ ์ ์ญ์ ๊ฑธ์น ์ฌ์ฉ์ ์ ๋ณด ๋๊ธฐํ ๋ถ์ฌ | ํ๋กํ ์ ๋ฐ์ดํธ ์ด๋ฒคํธ๋ฅผ ์ ์ญ ๊ตฌ๋ |
์ฑ์์ ๋ฐ์ํ ์ ์๋ ๋ชจ๋ ์ค์ ์ด๋ฒคํธ๋ฅผ sealed class๋ก ์ ์ํ์ฌ ํ์ ์์ ์ฑ์ ํ๋ณดํ์ต๋๋ค
@freezed
sealed class AppEvent with _$AppEvent {
// ํ๋กํ ๊ด๋ จ ์ด๋ฒคํธ
const factory AppEvent.profileUpdated() = ProfileUpdated;
// ์ปค๋ฎค๋ํฐ ๊ด๋ จ ์ด๋ฒคํธ
const factory AppEvent.postCreated(String postId) = PostCreated;
const factory AppEvent.postUpdated(String postId) = PostUpdated;
const factory AppEvent.postLiked(String postId) = PostLiked;
const factory AppEvent.postBookmarked(String postId) = PostBookmarked;
const factory AppEvent.commentAdded(String postId, String commentId) = CommentAdded;
const factory AppEvent.commentLiked(String postId, String commentId) = CommentLiked;
}
์ด๋ฒคํธ๋ฅผ ์ ์ญ์ ์ผ๋ก ๊ด๋ฆฌํ๋ Riverpod Provider
@Riverpod(keepAlive: true)
class AppEventNotifier extends _$AppEventNotifier {
final List<AppEvent> _events = [];
@override
List<AppEvent> build() => [];
void emit(AppEvent event) {
_events.add(event);
if (_events.length > 20) {
_events.removeAt(0);
}
state = List.from(_events);
print('๐ AppEventNotifier: ์ด๋ฒคํธ ๋ฐํ - $event');
}
bool hasEventOfType<T extends AppEvent>() {
return _events.any((event) => event is T);
}
bool hasPostEvent(String postId) {
return _events.any((event) =>
event is PostUpdated && event.postId == postId ||
event is PostLiked && event.postId == postId ||
// ...๋ค๋ฅธ postId ๊ด๋ จ ์ด๋ฒคํธ ์ฒดํฌ
);
}
}
// ํ๋กํ ์ ์ฅ ์ฑ๊ณต ์
if (result case AsyncData(:final value)) {
// ...๊ธฐ์กด ์ฝ๋...
// ์ฑ ์ด๋ฒคํธ ๋ฐํ: ํ๋กํ ์
๋ฐ์ดํธ๋จ
ref.read(appEventNotifierProvider.notifier).emit(
const AppEvent.profileUpdated(),
);
debugPrint('โ
ProfileEditNotifier: ํ๋กํ ์ ์ฅ ์ฑ๊ณต ๋ฐ ์ด๋ฒคํธ ๋ฐํ');
}
// ์ข์์ ์ฒ๋ฆฌ ๋ฐ ์ด๋ฒคํธ ๋ฐํ
Future<void> _handleLike() async {
// ...๊ธฐ์กด ์ฝ๋...
// ์ด๋ฒคํธ ๋ฐํ: ์ข์์ ์ํ ๋ณ๊ฒฝ๋จ
ref.read(appEventNotifierProvider.notifier).emit(
AppEvent.postLiked(_postId),
);
debugPrint('โ
CommunityDetailNotifier: ์ข์์ ํ ๊ธ ์๋ฃ ๋ฐ ์ด๋ฒคํธ ๋ฐํ');
}
// ๊ฒ์๊ธ ์์ฑ ์ฑ๊ณต ์
final createdPostId = await usecase.execute(/*...*/);
// ์ด๋ฒคํธ ๋ฐํ: ๊ฒ์๊ธ ์์ฑ๋จ
ref.read(appEventNotifierProvider.notifier).emit(
AppEvent.postCreated(createdPostId),
);
@override
CommunityListState build() {
// ...๊ธฐ์กด ์ฝ๋...
// ์ฑ ์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ถ๊ฐ
ref.listen(appEventNotifierProvider, (previous, current) {
if (previous != current) {
final eventNotifier = ref.read(appEventNotifierProvider.notifier);
// ํ๋กํ ๋ณ๊ฒฝ ์ด๋ฒคํธ๊ฐ ์์ผ๋ฉด - ์์ฑ์ ์ ๋ณด ๊ด๋ จ์ด๋ฏ๋ก ๋ชฉ๋ก ๊ฐฑ์
if (eventNotifier.hasEventOfType<ProfileUpdated>()) {
debugPrint('๐ CommunityListNotifier: ํ๋กํ ์
๋ฐ์ดํธ ๊ฐ์ง, ๋ชฉ๋ก ๊ฐฑ์ ');
Future.microtask(() => _fetch());
return;
}
// ๊ฒ์๊ธ ๊ด๋ จ ์ด๋ฒคํธ๊ฐ ์์ผ๋ฉด ๋ชฉ๋ก ๊ฐฑ์
final hasPostEvents = current.any((event) =>
event is PostLiked ||
event is PostBookmarked ||
event is CommentAdded ||
event is PostUpdated
);
if (hasPostEvents) {
debugPrint('๐ CommunityListNotifier: ๊ฒ์๊ธ ์ก์
์ด๋ฒคํธ ๊ฐ์ง, ๋ชฉ๋ก ๊ฐฑ์ ');
Future.microtask(() => _fetch());
}
}
});
// ...๋๋จธ์ง ์ฝ๋...
}
@override
CommunityDetailState build(String postId) {
// ...๊ธฐ์กด ์ฝ๋...
// ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ก ํ๋กํ ์
๋ฐ์ดํธ๋ฅผ ๊ฐ์งํ์ฌ ํ๋ฉด ์๋ก๊ณ ์นจ
ref.listen(appEventNotifierProvider, (previous, current) {
if (previous != current) {
final eventNotifier = ref.read(appEventNotifierProvider.notifier);
// ํ๋กํ ๋ณ๊ฒฝ ์ด๋ฒคํธ๊ฐ ์์ผ๋ฉด ํ๋ฉด ์๋ก๊ณ ์นจ
if (eventNotifier.hasEventOfType<ProfileUpdated>()) {
debugPrint('๐ CommunityDetailNotifier: ํ๋กํ ์
๋ฐ์ดํธ ๊ฐ์ง, ๊ฒ์๊ธ ์๋ก๊ณ ์นจ');
_loadAll();
}
}
});
// ...๋๋จธ์ง ์ฝ๋...
}
์ด ์ด๋ฒคํธ ์์คํ ๊ตฌํ์ ํตํด ๋ค์๊ณผ ๊ฐ์ ์ฅ์ ์ ์ป์ ์ ์์ต๋๋ค:
- ํ๋ฉด ๊ฐ ์ํ ๋๊ธฐํ: ํ ํ๋ฉด์์ ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋๋ฉด ๊ด๋ จ๋ ๋ชจ๋ ํ๋ฉด์ด ์๋์ผ๋ก ๊ฐฑ์ ๋ฉ๋๋ค.
- ๋ถ๋ฆฌ๋ ์ฑ ์: ๊ฐ ํ๋ฉด์ ์์ ์ ์ฑ ์๋ง ์ํํ๋ฉด์๋ ๋ค๋ฅธ ํ๋ฉด๊ณผ ๋๊ธฐํ๋ฉ๋๋ค.
- ์ฌ์ฉ์ ๊ฒฝํ ํฅ์: ๊ฒ์๊ธ์ ์ข์์/๋๊ธ ํ ๋ชฉ๋ก์ผ๋ก ๋์๊ฐ๋ฉด ์ฆ์ ๋ณ๊ฒฝ์ฌํญ์ด ๋ฐ์๋ฉ๋๋ค.
- ํ๋กํ ๋ณ๊ฒฝ ์ผ๊ด์ฑ: ํ๋กํ ์ ๋ณด ๋ณ๊ฒฝ์ด ์ฆ์ ์ฑ ์ ์ฒด์ ๋ฐ์๋ฉ๋๋ค.
- ๋๋ฒ๊น ์ฉ์ด์ฑ: ์ด๋ฒคํธ ํ๋ฆ์ ๋ก๊ทธ๋ก ์ถ์ ํ ์ ์์ด ๋ฌธ์ ๋ฐ๊ฒฌ์ด ์ฌ์์ง๋๋ค.
- AppEvent sealed class์ ์ ์ด๋ฒคํธ ํ์ ์ถ๊ฐ:
const factory AppEvent.newFeatureUpdated(String featureId) = NewFeatureUpdated;
- ์ฝ๋ ์์ฑ ์คํ (build_runner):
flutter pub run build_runner build --delete-conflicting-outputs
// ํน์ Notifier ๋ด๋ถ์์
void performAction() async {
// ... ์ก์
์ฒ๋ฆฌ ์ฝ๋ ...
// ์ด๋ฒคํธ ๋ฐํ
ref.read(appEventNotifierProvider.notifier).emit(
AppEvent.newFeatureUpdated("feature-123"),
);
}
@override
SomeState build() {
// ... ๋ค๋ฅธ ์ฝ๋ ...
// ์ด๋ฒคํธ ๊ตฌ๋
ref.listen(appEventNotifierProvider, (previous, current) {
if (previous != current) {
for (final event in current) {
if (event is NewFeatureUpdated) {
// ์ด๋ฒคํธ์ ๋ง๋ ์ฒ๋ฆฌ
_refreshFeature(event.featureId);
}
}
}
});
// ... ๋๋จธ์ง ์ฝ๋ ...
}
๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ: ์ด๋ฒคํธ ๊ฐ์๋ฅผ ์ ํํ์ฌ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ๊ด๋ฆฌํ์ธ์. ๋๋ฒ๊น ๋ก๊ทธ: ์ด๋ฒคํธ ๋ฐํ๊ณผ ๊ตฌ๋ ์ ๋ช ํํ ๋ก๊ทธ๋ฅผ ์ถ๊ฐํ์ธ์. ์ด๋ฒคํธ ์ ์: ์ด๋ฒคํธ๋ ํ์ํ ์ต์ํ์ ์ ๋ณด๋ง ํฌํจํด์ผ ํฉ๋๋ค. ๊ณผ๋ํ ๊ฐฑ์ ๋ฐฉ์ง: ๋ชจ๋ ์ด๋ฒคํธ์ ๋ํด ๊ฐฑ์ ํ์ง ๋ง๊ณ ํ์ํ ์ด๋ฒคํธ๋ง ๊ตฌ๋ ํ์ธ์. ํ์ ์์ ์ฑ: sealed class์ ํจํด ๋งค์นญ์ ํ์ฉํด ํ์ ์์ ์ฑ์ ํ๋ณดํ์ธ์.
์ด ๊ฐ์ด๋๋ฅผ ์ฐธ๊ณ ํ์ฌ Firebase์ ์ฐ๋๋ ์ํ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ด๋ฆฌํ๊ณ , ์ฑ ์ ์ฒด์์ ๋ฐ์ดํฐ ์ผ๊ด์ฑ์ ์ ์งํ์ธ์.