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
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
HyunWoo Lee
December 21, 2024
Programming
0
600
선언형 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
220
How Android Uses Data Structures Behind The Scenes
l2hyunwoo
1
680
Understanding Kotlin Multiplatform (Busan)
l2hyunwoo
0
69
Understanding Kotlin Multiplatform
l2hyunwoo
0
320
파급효과: From AI to Android Development
l2hyunwoo
0
310
선언형 UI를 학습할 때 알아둬야하는 키워드들
l2hyunwoo
0
510
Essential concepts to know when learning Declarative UI
l2hyunwoo
2
1.6k
React Native under the hood
l2hyunwoo
0
160
유연한 Composable 설계
l2hyunwoo
0
740
Other Decks in Programming
See All in Programming
AgentCoreとHuman in the Loop
har1101
5
210
フロントエンド開発の勘所 -複数事業を経験して見えた判断軸の違い-
heimusu
7
2.7k
CSC307 Lecture 07
javiergs
PRO
0
530
例外処理とどう使い分ける?Result型を使ったエラー設計 #burikaigi
kajitack
16
5.9k
CSC307 Lecture 02
javiergs
PRO
1
770
re:Invent 2025 トレンドからみる製品開発への AI Agent 活用
yoskoh
0
710
humanlayerのブログから学ぶ、良いCLAUDE.mdの書き方
tsukamoto1783
0
170
React 19でつくる「気持ちいいUI」- 楽観的UIのすすめ
himorishige
11
5.9k
AI Agent の開発と運用を支える Durable Execution #AgentsInProd
izumin5210
7
2.2k
それ、本当に安全? ファイルアップロードで見落としがちなセキュリティリスクと対策
penpeen
7
2.4k
Kotlin Multiplatform Meetup - Compose Multiplatform 외부 의존성 아키텍처 설계부터 운영까지
wisemuji
0
180
Oxlintはいいぞ
yug1224
5
1.2k
Featured
See All Featured
Build The Right Thing And Hit Your Dates
maggiecrowley
38
3k
GraphQLの誤解/rethinking-graphql
sonatard
74
11k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
0
250
Bash Introduction
62gerente
615
210k
The browser strikes back
jonoalderson
0
350
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
150
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
2.9k
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
150
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
61
52k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.6k
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)