Compose UI는 Immutable하고 직접 업데이트할 수 없다
UI 상태를 통해 Compose가 변경된 부분만 다시 그린다
또한 Composable 함수는 기본적으로 상태는 아래로 흐르고 이벤트는 위로 흐른다
예시) 상태를 입력으로 받아(name) 이벤트를 노출하는(onValueChange) Composable
var name by remember { mutableStateOf("") }
OutlinedTextField(
value = name,
onValueChange = { name = it },
label = { Text("Name") }
)
Compose에는 단방향 데이터 흐름이 적합하다
단방향 데이터 흐름 (Unidirectional Data Flow)
상태는 아래로 이동하고 이벤트는 위로 이동하는 디자인 패턴
Compose에서 UDF가 동작하는 방식
상태는 State 객체에 저장된다 (mutableStateOf 함수 사용)
상황에 따라 remember, rememberSaveable을 사용해 컴포지션 내에서 상태 유지
상태는 아래로 흘러 각 Composable에서 필요한 상태를 입력으로 받는다
상태가 변경되면 상태를 사용하는 Composable 함수들이 다시 그려진다
이벤트(사용자 입력, 네트워크 요청 등)는 위로 흘러 ViewModel에서 이벤트를 처리한다
이벤트 처리 후 상태가 변경되면, 상태는 다시 아래로 흘러 UI 업데이트
Compose에서 UDF 사용 시 장점
테스트 용이 - 각 Composable을 독립적으로 테스트 가능
유지 보수 향상 - 코드가 간결하고 수정하기 쉽다
UI 일관성 향상 - 상태가 변경되면 UI가 변경되는 일관성
Composable 매개변수 정의
매개변수를 정의할 때 고려할 사항
Composable 재사용 가능성
상태 매개변수가 Composable 성능에 미치는 영향
각 Composable에는 최소한의 정보만 가지는 것이 좋다
@Composable
fun Header(title: String, subtitle: String) {
// title, subtitle 변경 시 recompose
}
@Composable
fun Header(news: News) {
// 새로운 News 전달 시 recompose
}
Compose 이벤트와 상태관리
이벤트는 UI 상태를 변경시키고 ViewModel은 이를 처리하여 UI 상태 업데이트
중요한 점은, UI Layer는 이벤트 핸들러 외부에서 상태를 변경하지 않아야 한다
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
// UI 레이어에서 상태를 직접 변경. 버그 유발 가능
// count++
Column {
Text("Count: $count")
Button(onClick = {
// 이벤트 핸들러를 통해 상태 변경
count++
}) {
Text("Increment")
}
}
}
또한 Immutable 값을 상태, 이벤트 핸들러 람다에 전달하는 것이 좋다
이로 인해
Composable 재사용으로 인해 재사용성 향상
UI가 상태 값을 직접 변경하지 않음
상태가 다른 스레드에서 변경되지 않아 동시 실행 문제가 없다
의 이점이 있다
@Composable
fun MyAppTopAppBar(topAppBarText: String, onBackPressed: () -> Unit) {
TopAppBar(
title = {
Text(
text = topAppBarText,
textAlign = TextAlign.Center,
modifier = Modifier
.fillMaxSize()
.wrapContentSize(Alignment.Center)
)
},
navigationIcon = {
IconButton(onClick = onBackPressed) {
Icon(
Icons.Filled.ArrowBack,
contentDescription = localizedString
)
}
},
// ...
)
}
또한 ViewModel과 mutableStateOf를 사용하여 앱에 단방향 데이터 흐름을 도입할 수 있다
- UI 상태는 관찰 가능한 상태 홀더 (StateFlow, LiveData)를 통해 노출
- ViewModel은 이벤트를 처리하고, 이벤트를 기반으로 상태 홀더를 업데이트
예시) 로그인 화면
상태
- SignedOut (로그아웃 상태)
- InProgress (로그인 진행 중)
- Error (오류 발생)
- SignedIn (로그인 완료)
// 위 상태를 sealed class로 모델링
sealed class LoginUiState() {
object SignedOut : LoginUiState() // 로그아웃 상태
object InProgress : LoginUiState() // 로그인 진행 중
data class Error(val message: String) : LoginUiState() // 오류 발생
object SignedIn : LoginUiState() // 로그인 완료
}
class MyViewModel : ViewModel() {
private val _uiState = mutableStateOf<LoginUiState>(LoginUiState.SignedOut)
val uiState: State<LoginUiState>
get() = _uiState
// ...
}
'Compose' 카테고리의 다른 글
[ComposeInternals] Composable 함수들 (0) | 2025.03.03 |
---|---|
[Compose] Compose 아키텍처 레이어링 (0) | 2025.02.23 |
[Compose] UI 상태 저장 및 복원 (0) | 2025.02.22 |
[Compose] 상태 호이스팅(State Hoisting) (0) | 2025.02.21 |
[Compose] 상태 관리 (0) | 2025.02.10 |