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
HyunWoo Lee
December 21, 2024
Programming
640
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
선언형 UI에서의 상태관리
GDG Devfest Songdo 2024에서 진행한 선언형 UI에서의 상태관리의 Speaker Deck입니다.
HyunWoo Lee
December 21, 2024
More Decks by HyunWoo Lee
See All by HyunWoo Lee
Navigating Dependency Injection with Metro
l2hyunwoo
1
350
How Android Uses Data Structures Behind The Scenes
l2hyunwoo
1
770
Understanding Kotlin Multiplatform (Busan)
l2hyunwoo
0
100
Understanding Kotlin Multiplatform
l2hyunwoo
0
360
파급효과: From AI to Android Development
l2hyunwoo
0
360
선언형 UI를 학습할 때 알아둬야하는 키워드들
l2hyunwoo
0
550
Essential concepts to know when learning Declarative UI
l2hyunwoo
2
1.7k
React Native under the hood
l2hyunwoo
0
210
유연한 Composable 설계
l2hyunwoo
0
780
Other Decks in Programming
See All in Programming
メソッドのジェネリクスでGoの夢は広がるか? / Kyoto.go #65
utgwkk
3
1k
正しくソフトウェアを作る、前提を疑うための認知の視点 / doubt-premise
minodriven
21
7.1k
JavaDoc 再入門
nagise
1
440
Dataformのリポジトリを立ち上げるときにまずやること / dataform-day0-2026
snhryt
0
200
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
800
ローカルLLMを使ってB2Bサービスを作っていての学び
yaotti
0
220
才能?センス?知らん、 続けたもん勝ちだ。-- 結婚・出産・癌を越えてなお、私がプロダクトを創り続ける理由
16bitidol
1
610
Vite+ Unified Toolchain for the Web
naokihaba
0
410
SLOをサービス品質の共通言語にするために 取り組んできたこと
wakana0222
0
190
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
1
320
TSKaigi Night Talks 2026_TypeScriptでサプライチェーンの整合性を型に閉じ込める
geekplus_tech
0
420
A2UI という光を覗いてみる
satohjohn
1
170
Featured
See All Featured
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
What's in a price? How to price your products and services
michaelherold
247
13k
Optimising Largest Contentful Paint
csswizardry
37
3.7k
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Being A Developer After 40
akosma
91
590k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.2k
Automating Front-end Workflow
addyosmani
1370
210k
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
380
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
860
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
340
GitHub's CSS Performance
jonrohan
1033
470k
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)