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
선언형 UI에서의 상태관리
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
HyunWoo Lee
December 21, 2024
Programming
0
610
선언형 UI에서의 상태관리
GDG Devfest Songdo 2024에서 진행한 선언형 UI에서의 상태관리의 Speaker Deck입니다.
HyunWoo Lee
December 21, 2024
Tweet
Share
More Decks by HyunWoo Lee
See All by HyunWoo Lee
Navigating Dependency Injection with Metro
l2hyunwoo
1
250
How Android Uses Data Structures Behind The Scenes
l2hyunwoo
1
690
Understanding Kotlin Multiplatform (Busan)
l2hyunwoo
0
75
Understanding Kotlin Multiplatform
l2hyunwoo
0
320
파급효과: From AI to Android Development
l2hyunwoo
0
320
선언형 UI를 학습할 때 알아둬야하는 키워드들
l2hyunwoo
0
520
Essential concepts to know when learning Declarative UI
l2hyunwoo
2
1.6k
React Native under the hood
l2hyunwoo
0
170
유연한 Composable 설계
l2hyunwoo
0
740
Other Decks in Programming
See All in Programming
AIとペアプロして処理時間を97%削減した話 #pyconshizu
kashewnuts
1
200
DSPy入門 Pythonで実現する自動プロンプト最適化 〜人手によるプロンプト調整からの卒業〜
seaturt1e
1
530
AI駆動開発の本音 〜Claude Code並列開発で見えたエンジニアの新しい役割〜
hisuzuya
4
480
DevinとClaude Code、SREの現場で使い倒してみた件
karia
1
920
「やめとこ」がなくなった — 1月にZennを始めて22本書いた AI共創開発のリアル
atani14
0
350
Codexに役割を持たせる 他のAIエージェントと組み合わせる実務Tips
o8n
0
220
AIプロダクト時代のQAエンジニアに求められること
imtnd
2
700
SourceGeneratorのマーカー属性問題について
htkym
0
140
nilとは何か 〜interfaceの構造とnil!=nilから理解する〜
kuro_kurorrr
3
1.6k
Rails Girls Tokyo 18th GMO Pepabo Sponsor Talk
yutokyokutyo
0
200
AHC061解説
shun_pi
0
320
モジュラモノリスにおける境界をGoのinternalパッケージで守る
magavel
0
3.4k
Featured
See All Featured
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
140
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
60
42k
Navigating Weather and Climate Data
rabernat
0
130
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
1
1.4k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.1k
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
What does AI have to do with Human Rights?
axbom
PRO
1
2k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.7k
Embracing the Ebb and Flow
colly
88
5k
Information Architects: The Missing Link in Design Systems
soysaucechin
0
810
The Pragmatic Product Professional
lauravandoore
37
7.2k
Transcript
Incheon ࢶഋ UIীࢲ ࢚కҙܻ - Circuitҗ Rinਸ बਵ۽ അ Android/React
Native Developer, Viva Republica(Toss) Organizer, Kotlin User Groups Seoul/GDG Incheon
࢚కҙܻ ѐ֛җ ࢎ ݾର ҙܻೡ “࢚క” ঌইࠁӝ ࢚క ઑӘ
؊ ੜ ҙܻ ೧ࠁӝ
Speakerdeck Youtube ࢶഋ UI ೨बѐ֛
࢚కҙܻ ѐ֛җ ࢎ
Before Compose class SampleActivity: AppCompatActivity() { private var name =
"" override fun onCreate(bundle: SavedInstanceState?) { super.onCreate(bundle) // ࢲߡాन APIService.getMyName().enqueue(object: Callback { override fun onResponse(ޤदӽ) { name = response.body().name updateUi() // binding.tv.text = name } }) } }
Before Compose • ѐߊо ߸ࣻܳ ߸҃ೞҊ UI ࢚కܳ ߸҃ೞب۾
٘ܳ ࢿ೧ঠೣ • ߸ࣻо ചݶ ߸҃ਸ दఃחؘ ਃبо ڄয • ചݶਸ ߸҃ೞח Ѫ ߸ࣻ ч ইצ ѐߊ
Before Compose - DataBinding class SampleActivity: AppCompatActivity() { private val
viewModel by viewModels() private lateinit var binding: ActivitySampleBinding override fun onCreate(bundle: SavedInstanceState?) { super.onCreate(bundle) binding = DataBindingUtil.setContentView(this, R.layout.ui) binding.viewModel = viewModel } } <layout> <data> <variable name=“vm” type=“com.sample.ViewModel” /> </data> <TextView <!— ࢤۚ —> android:text=“@{vm.user.nam e}” /> </layout>
Data Binding ߸ࣻܳ ߸҃݅ ೧ب ചݶ ࢚కо ߸҃ؽ ߸ࣻо ചݶ
“࢚క”о غب۾ ࢸ҅ ߑೱ ߸҃ , ചݶ ࢚క ߸҃ о ѐߊীࢲ दझమਵ۽ بؽ بੋ ࠽٘ఋ ࢚थҗ ೧ةೞӝ য۰ ী۞ झఖ ۨझ Data Binding -> View Bindingਵ۽ ֈযоח ୶ࣁ Ӓۢীب ࠛҳೞҊ ѐߊо ചݶ ߸ࣻо “࢚క”۽ ੋधೞѱ ػ ࣁ
Compose بੑ റ @Composable fun SampleText() { var text by
remember { mutableStateOf("") } LaunchedEffect(Unit) { text = APIService.getName().await() } TextField(value = text, onValueChange = { text = it }) }
Compose ߸ࣻܳ ߸҃݅ ೧ب ചݶ ࢚కо ߸҃ؽ ୶оੋ ࠽٘ కझ
হ ߸ࣻо ചݶ ࢚కо ؽ
Compose ߸ࣻо ചݶ ࢚క Android Developers - Ui State
࢚క ખ ؊ ࣁ ঌইࠁӝ
࢚కо ޤਃ? UIܳ അೞח ݽٚ ؘఠ
࢚కҙܻо ޤਃ? UIܳ അೞח ݽٚ ؘఠ ܳ ҙܻೞח ߑߨۿ
ࢤпࠁ ҙܻ೧ঠೡ ࢚క ઙܨח নೞ ഥਗоੑ ੑ۱ Form • ܴ/ݫੌ
ࣗ/࠺ߣഐ ١ ੑ۱ UI • ݫੌࣗ ࠂ ৈࠗ • ࠺ߣഐ Ѩૐ • ࠺ߣഐ ഛੋҗ ࠺ߣഐ ੌ ৈࠗ • ডҙ ز
ࢤпࠁ ҙܻ೧ঠೡ ࢚క ઙܨח নೞ
࢚కҙܻ Key Point ؘఠܳ য٣ী, যڌѱ ਤदఃחо?
࢚క৬ ࢚క
࢚క৬ ࢚క ࢚కо ־ҳীѱ ҕਬغҊ חо ೞա ஹನք && ध
ஹನքٜীѱ ҕਬ - ࢚క ஹನքٜ ࢎਊೡ ࣻ ѱ ҕਬ - ࢚క
࢚క(Global State) @Composable fun TodoTheme( darkTheme: Boolean = false,
content: @Composable () -> Unit ) { val colors = todoColors() val typography = TodoTypography() ProvideTodoColorAndTypography(colors, typography){ MaterialTheme(content = content) } }
উ٘۽٘ীࢲ ࢚కҙܻ
উ٘۽٘ীࢲ ࢚కҙܻ
Configuration Change CompositionLocal۽ ׳غח ч ী غפө Config Change۽ ч
ࠛউ೧ݶ ஹನքী ೱ -> জ উࢿ ೞ ۽ࣁझ ࢤݺӝী উਵ۽ ؘఠ द ਊ ޙઁ rememberSavableਸ ഝਊೞݶ 1MB ղ۽ ؘఠܳ ೧ঠೞחؘ ਗೞח ݅ఀ ؘఠܳ ਸ ೞо ࢚ ޅೠ Exception ఠ ࣻ উ٘۽٘ীࢲ ࢚కҙܻ
࢚కҙܻ Android OS: ॄب જؘ, ॄۄ
࢚క ੜ ҙܻೞӝ
ࠗ࠙ ࢚కҙܻ ViewModel ❤
݈ ViewModelী ֍חѱ ୭ࢶ? Configuration Changeী ٮۄࢲ ч ߸҃೧ঠೡ ࣻ
ѓ۟द Fold৬ э ҃ ਵݶ Phone UI, ಟݶ Tablet UI ࠁৈঠೞח ா झ ߊࢤ, ۠ ؘఠܳ Config Change উѱ فݶ য়۰ ী۞ ߊࢤ ܲ ஹನքٜী ࠛਃೠ ࠁܳ ֈѹ п ёח ೞѱ ҙ҅ػ ܲ ёٜী ೧ࢲ ઁೠػ ध݅ਸ оઉঠ ೠ. (Law of Demeter)
None
StateHolder Class @Stable class NiaAppState( val navController: NavHostController, coroutineScope: CoroutineScope,
networkMonitor: NetworkMonitor, userNewsResourceRepository: UserNewsResourceRepository, timeZoneMonitor: TimeZoneMonitor, ) { private val previousDestination = mutableStateOf<NavDestination?>(null) ……
StateHolder Class @Composable fun rememberNiaAppState( … ): NiaAppState { return
remember { NiaAppState( navController = navController, coroutineScope = coroutineScope, networkMonitor = networkMonitor, userNewsResourceRepository = userNewsResourceRepository, timeZoneMonitor = timeZoneMonitor, )
State Holder https://developer.android.com/topic/architecture/ui-layer/ stateholders
Circuit ନݡೞӝ
Circuit? Circuit is a simple, lightweight, and extensible framework for
building Kotlin applications that’s Compose from the ground up.
Circuit? Circuit рױೞҊ о߶ݴ ഛ оמೠ ۨਕ۽, A-Zө Compose݅ਸ ഝਊೞৈ
Kotlin গܻா࣌ਸ ҳ୷ೡ ࣻ णפ.
Circuit? ࢚కҙܻ ߑध݅ਸ ۽ ঠӝ ೞӝ ٸޙী ജ҃ࢸ ١ ҳഅী
ਃೠ ࣁࠗࢎ೦ٜ ઁ৻ೞणפ
Circuit?
Circuit?
Circuit рױೠ ҳઑب
Screen data class CounterScreen(val initialCount: Int): Screen data class DetailScreen(val
id: Long): Screen data class FavoriteScreen: Screen
CircuitUiState, CircuitUiEvent sealed inte rf ace State : CircuitUiState {
data object Loading : State data object NoFavorites : State data class Results( val list: List<Favorite>, val eventSink: (Event) -> Unit ) : State } sealed inte rf ace Event : CircuitUiEvent { data class ClickFavorite(id: Long): Event }
@Composable fun CounterPresenter(): CounterState { var count by rememberSaveable {
mutableStateOf(0) } return CounterState(count) { event -> when (event) { CounterEvent.Increment -> count++ CounterEvent.Decrement -> count-- } } } Presenter
@Composable fun CounterPresenter(): CounterState { var count by rememberRetained {
mutableStateOf(0) } return CounterState(count) { event -> when (event) { CounterEvent.Increment -> count++ CounterEvent.Decrement -> count-- } } } Presenter
rememberRetained
// CircuitUiState ఋੑ expo rt inte rf ace CounterState {
value: number } // CircuitUiState ୡӝ ё const initialState: CounterState = { value: 0, } Redux Toolkitҗ Presenter
// Circuit presenter expo rt const counterSlice = createSlice({ name:
'counter', // Updateغח state initialState, reducers: { // event ࠗ࠙ increment: (state) => { state.value += 1 }, decrement: (state) => { state.value -= 1 } } ) Redux Toolkitҗ Presenter
@CircuitInject(FavoriteScreen::class, ActivityRetainedComponent::class) @Composable fun FavoritesList(state: FavoritesScreen.State) { when (state) {
Loading -> Text(text = stringResource(R.string.loading_favorites)) NoFavorites -> Text( modi fi er = Modi fi er.testTag("no favorites"), text = stringResource(R.string.no_favorites) ) is Results -> { LazyColumn { items(state.list) { Favorite(it, state.eventSink) } } } } } Screen
Circuitী ೠ рۚೠ ࣗх • ഋ জҗ э ҃, ఋੑ/ҳഅী
ೠ ӏઁٜ ࢤೞח ٘ ాੌࢿҗ оةࢿਸ ֫ৈ ࣻ • Unit Testب рױೞѱ ࢿೡ ࣻ • Compose runtimeਸ ഝਊ೧ࢲ ߈ഋ ࢚కܳ ઁೡ ࣻ ח Ѫী
Circuitী ೠ рۚೠ ࣗх • Ѧ ਊೡ ࣻ ח ഥࢎо
ݻա ਸө? • নೠ بҳٜ(Flow, Rx, Legacy View ١)җ interopਸ ೡ ࣻ ݅, ܳ interopೞӝ ਤ೧ ٘ח ݆ࣻ ҕٜࣻਸ ࢤп೧ঠؽ • ъઁ۽ ҳഅ/ࢎਊ೧ঠೞח Ѫٜ(Presenter, Navigator ١) ݆ই पઁ۽ ۽؋࣌ী ਊؼ݅ೠח ޙ
@Composable fun ScreenA() { var isB by rememberRetained { mutableStateOf(true)
} rememberRetained{ "A" } if(isB) { rememberRetained{ "B" } } else { rememberRetained{ "C" } } } takahirom/Rin
উ٘۽٘ীࢲ ࢚కҙܻ ࢚క৬ ࢚క ࢚కܳ ࠁ ؊ ੜ ҙܻೠ ߑߨ
Summary
Thank you Incheon HyunWoo Lee Android(React Native) Developer, Viva Republica(Toss)