Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
layerx_20241129.pdf
Search
Kyohei Ito
November 29, 2024
Programming
520
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
layerx_20241129.pdf
Kyohei Ito
November 29, 2024
More Decks by Kyohei Ito
See All by Kyohei Ito
flutter_kaigi_2025.pdf
kyoheig3
2
1.1k
flutterkaigi_2024.pdf
kyoheig3
0
1.9k
flutter_kaigi_2021.pdf
kyoheig3
0
1.2k
flutter_kmm_1.pdf
kyoheig3
1
1.2k
ca.swift_10.pdf
kyoheig3
0
720
iosdc_2018.pdf
kyoheig3
2
3.2k
orecon_vol1.pdf
kyoheig3
4
1.8k
iosdc_2017.pdf
kyoheig3
4
940
ca.swift_2.pdf
kyoheig3
9
1.4k
Other Decks in Programming
See All in Programming
AI時代に設計が 最大の生産性レバーになる 意図駆動開発とデータを消さない設計|Don't Delete Your Data or Your Intent — Design as the Deepest Lever in the AI Era
tomohisa
1
730
Claude CodeとAgentCore Gatewayを繋ぐ際の認証認可 / Authentication and authorization when connecting Claude Code with AgentCore Gateway
har1101
1
260
属人化した知識を、 AIが辿れる地図にする
pkshadeck
PRO
1
150
作るコストが小さくなった時代 幸せに働くために改めて考えたいこと 〜エンジニアとして価値を出し続けるために注視している二分野〜
yuppeeng
0
190
Terraform標準の組織で AWS CDKをどう使うか
mu7889yoon
1
490
OpenSpecのproposalにbrainstormingを持たせてみた
tigertora7571
1
210
Android CLI
fornewid
0
210
Laravel Boostに学ぶ、AIにPHPを書かせる技術 〜OSSの実装から蒸留するエージェント制御の王道〜
kentaroutakeda
3
670
壊れたパーサから始める関数型設計と構成的なパーサ #fp_matsuri
raiga0310
2
450
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
540
Google Apps Script で Ruby を動かす
kawahara
0
140
AI Engineeringは、AIプロダクトだけのものか? 〜AIがソフトウェアを作る時代の新しい当たり前〜 / No AI in your product. AI Engineering in your development.
rkaga
4
380
Featured
See All Featured
Context Engineering - Making Every Token Count
addyosmani
9
1k
Balancing Empowerment & Direction
lara
6
1.2k
Mind Mapping
helmedeiros
PRO
1
300
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
470
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
Utilizing Notion as your number one productivity tool
mfonobong
4
520
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
400
エンジニアに許された特別な時間の終わり
watany
108
250k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
760
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.8k
Amusing Abliteration
ianozsvald
1
240
Transcript
UI ίϯϙʔωϯτ͔Βߟ͑Δ ΞʔΩςΫνϟ Flutter ΞʔΩςΫνϟઃܭͷ࠷લઢ
About Me ҏ౻ ګฏ גࣜձࣾαΠόʔΤʔδΣϯτ Github: KyoheiG3 X: KyoheiG3
MVVM BLoC Redux MVC Flux Provider
MVVM BLoC Redux MVC Flux Provider
Flutter ެࣜυΩϡϝϯτ https://docs. fl utter.dev/app-architecture
MVVM • Ͳ͏͍͏୯ҐͰׂΛ͚Δ͖͔ʁ
Service • ଓ͖͢σʔλιʔεͷ୯ҐͰଘࡏ͢Δ͜ͱ͕·͍͠
Repository • ΞϓϦͰѻ͏σʔλͷछྨ͝ͱʹ༻ҙ͢Δ
Data layer • σʔλσʔλιʔεͷ୯ҐͰׂΛ͚ͯѻ͏͜ͱ͕Ͱ͖ͦ͏
ViewModel • View 1ͭʹ͖ͭ ViewModel 1ͭʹͳΔ
View • Widget 1ͭʹ͖ͭ ViewModel 1ͭͰͳ͍ • ΞϓϦͷػೳʹରͯ͠ 1ͭଘࡏ͢Δʢʁʣ
UI layer • ΞϓϦͷػೳʹରͯ͠ 1ͭଘࡏ͢Δʢʁʣ
͓Βͤը໘ 1ը໘ʹ 1ػೳ
͓ؾʹೖΓҰཡը໘ ಉ͡ػೳͷཏྻ
ϗʔϜը໘ ༷ʑͳػೳͷू߹ମ
ϗʔϜը໘ UI layer UI ίϯϙʔωϯτ ͷ୯ҐͰ࡞Δ
Flutter ެࣜυΩϡϝϯτ https://docs. fl utter.dev/cookbook/ architecture/optimistic-state
Example feature: a subscribe button ը૾ग़లɿOptimistic State / https://docs. fl
utter.dev/cookbook/architecture/optimistic-state
FlutterKaigi 2024
FlutterKaigi 2024
ొਓ
্Ґͷ ViewModel ͕Լͷ ViewModel Λ࡞Δύλʔϯ
্Ґͷ ViewModel ͕Լͷ ViewModel Λ࡞Δύλʔϯ @riverpod Future<HomeViewModel> homeViewModel(HomeViewModelRef ref) async
{ final favorites = await ref.watch(favoriteListStateNotifierProvider.future); final notifications = await ref.watch(notificationListStateNotifierProvider.future); return HomeViewModel( favorite: HomeFavoriteViewModel(favorites: favorites), notification: HomeNotificationViewModel(notifications: notifications), ); }
্Ґͷ ViewModel ͕Լͷ ViewModel Λ࡞Δύλʔϯ class HomePage extends ConsumerWidget {
const HomePage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final homeViewModel = ref.watch(homeViewModelProvider); return homeViewModel.when( data: (viewModel) { return Column( children: [ HomeFavoriteList(model: viewModel.favorite), HomeNotificationList(model: viewModel.notification), ], ); }, ); } }
ίϯϙʔωϯτຖʹ ViewModel Λ࡞Δύλʔϯ
ίϯϙʔωϯτຖʹ ViewModel Λ࡞Δύλʔϯ class HomeNotificationList extends ConsumerWidget { const HomeNotificationList({super.key});
@override Widget build(BuildContext context, WidgetRef ref) { final notificationListViewModel = ref.watch(notificationListViewModelProvider); return notificationListViewModel.when( data: (viewModel) { return Column( children: [ HomeNotificationItem(item: viewModel.notifications[0]), HomeNotificationItem(item: viewModel.notifications[1]), ], ); }, ); } }
ίϯϙʔωϯτຖʹ ViewModel Λ࡞Δύλʔϯ class HomeFavoriteList extends ConsumerWidget { const HomeFavoriteList({super.key});
@override Widget build(BuildContext context, WidgetRef ref) { final favoriteListViewModel = ref.watch(favoriteListViewModelProvider); return favoriteListViewModel.when( data: (viewModel) { return Column( children: [ HomeFavoriteItem(item: viewModel.favorites[0]), HomeFavoriteItem(item: viewModel.favorites[1]), ], ); }, ); } }
ίϯϙʔωϯτຖʹ ViewModel Λ࡞Δύλʔϯ class HomePage extends StatelessWidget { const HomePage({super.key});
@override Widget build(BuildContext context) { return const Column( children: [ HomeFavoriteList(), HomeNotificationList(), ], ); } }
Provider Λ্Ґʹ͑Δ
Provider Λ্Ґʹ͑Δ @riverpod Future<HomeFavoriteListViewModel> favoriteListViewModel(FavoriteListViewModelRef ref) async { final state
= await ref.watch(favoriteListStateNotifierProvider.future); return HomeFavoriteListViewModel( favorites: state.favorites, ); } @riverpod Future<HomeNotificationListViewModel> notificationListViewModel(NotificationListViewModelRef ref) async { final state = await ref.watch(notificationListStateNotifierProvider.future); return HomeNotificationListViewModel( notifications: state.notifications, ); }
@riverpod Future<HomeFavoriteListViewModel> favoriteListViewModel(FavoriteListViewModelRef ref) async { final state = await
ref.watch(favoriteListStateNotifierProvider.future); return HomeFavoriteListViewModel( favorites: state.favorites, ); } @riverpod Future<HomeNotificationListViewModel> notificationListViewModel(NotificationListViewModelRef ref) async { final state = await ref.watch(notificationListStateNotifierProvider.future); return HomeNotificationListViewModel( notifications: state.notifications, ); } favoriteListStateNotifierProvider.future notificationListStateNotifierProvider.future Provider Λ্Ґʹ͑Δ 4UBUFΛϦϑϨογϡ Ͱ͖Δͱྑͦ͞͏
Provider Λ্Ґʹ͑Δ class HomePage extends ConsumerWidget { const HomePage({super.key}); @override
Widget build(BuildContext context, WidgetRef ref) { return RefreshIndicator( onRefresh: () => ( ref.refresh(favoriteListStateNotifierProvider.future), ref.refresh(notificationListStateNotifierProvider.future), ).wait, child: const Column( children: [ HomeFavoriteList(), HomeNotificationList(), ], ), ); } }
ϗʔϜը໘ ௨৴ͦͷଞͷॲཧ͕ྃ ͨ͠ॱʹߋ৽͞Εͯ͠·͏
Provider Λ Override ͢Δύλʔϯ
Provider Λ Override ͢Δύλʔϯ @riverpod Future<NotificationListViewModel> homeNotificationListViewModel(_) => throw UnimplementedError();
class HomeNotificationList extends ConsumerWidget { const HomeNotificationList({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final notificationListViewModel = ref.watch(homeNotificationListViewModelProvider); return notificationListViewModel.when( data: (viewModel) { return Column( children: [ HomeNotificationItem(item: viewModel.notifications[0]), HomeNotificationItem(item: viewModel.notifications[1]), ], ); }, ); } }
Provider Λ Override ͢Δύλʔϯ @riverpod Future<FavoriteListViewModel> homeFavoriteListViewModel(_) => throw UnimplementedError();
class HomeFavoriteList extends ConsumerWidget { const HomeFavoriteList({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final favoriteListViewModel = ref.watch(homeFavoriteListViewModelProvider); return favoriteListViewModel.when( data: (viewModel) { return Column( children: [ HomeFavoriteItem(item: viewModel.favorites[0]), HomeFavoriteItem(item: viewModel.favorites[1]), ], ); }, ); } }
Provider Λ Override ͢Δύλʔϯ return FutureBuilder( future: ( ref.watch(favoriteListViewModelProvider.future), ref.watch(notificationListViewModelProvider.future),
).wait, builder: (context, snapshot) { final data = snapshot.data!; return ProviderScope( overrides: [ homeFavoriteListViewModelProvider.overrideWith((_) => data.$1), homeNotificationListViewModelProvider.overrideWith((_) => data.$2), ], child: const Column( children: [ HomeFavoriteList(), HomeNotificationList(), ], ), ); }, );
Provider Λ Override ͢Δύλʔϯ return FutureBuilder( future: ( ref.watch(favoriteListViewModelProvider.future), ref.watch(notificationListViewModelProvider.future),
).wait, builder: (context, snapshot) { final data = snapshot.data!; return ProviderScope( overrides: [ homeFavoriteListViewModelProvider.overrideWith((_) => data.$1), homeNotificationListViewModelProvider.overrideWith((_) => data.$2), ], child: const Column( children: [ HomeFavoriteList(), HomeNotificationList(), ], ), ); }, );
·ͱΊ • UI layer ΛͲͷΑ͏ͳ୯ҐͰ͚Δͷ͔Λߟ͑ͳ͕Βઃܭ͢Δ • View ಉ࢜Ͱ ViewModel ΛόέπϦϨʔ͠ͳ͍ํ๏ʹઓ͢Δ
• UI ͷίϯϙʔωϯτԽͷΈ͕Ͱ͖ͨΒɺෳࡶͰͳ͍ը໘ͰͳΔ ͘ಉ͡ΈΛར༻࣮ͨ͠ʹ͢Δ
Thanks !