Jetpack Compose를 사용하면서 가장 기본적이면서도 중요한 개념 중 하나가 State이다. 또한 이를 컴포저블 간에 깔끔하게 관리하기 위한 패턴으로 State Hoisting이 널리 사용되고 있다. 이 글에서는 Compose의 State가 무엇이고, 왜 State Hoisting이 필요한지, 그리고 실제로 어떻게 사용하는지 정리해보려고 한다.
1. Compose에서 State란?
Compose는 선언형 UI 프레임워크이다. "상태(State)가 바뀌면 UI를 다시 그린다"는 철학에 따라 작동한다.
State는 UI를 그리는 데 필요한 데이터를 의미한다. 즉, 화면에 표시되는 값이나, 사용자의 입력, 버튼 클릭 여부 등이 모두 상태로 표현될 수 있다.
Compose에서는 @Composable 함수 안에서 remember와 mutableStateOf를 사용하여 상태를 정의할 수 있습니다.
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text(text = "Count: $count")
}
}
위 예시에서 count는 버튼을 누를 때마다 증가하는 State이다.
mutableStateOf(0)를 통해 초기값을 0으로 설정했고, remember를 통해 recomposition 시에도 상태를 유지할 수 있도록 했다.
2. State Hoisting이란?
State Hoisting은 "상태를 컴포저블 내부가 아니라 외부(부모)로 끌어올려서 관리하는 것"을 의미한다.
왜 이렇게 해야 할까?
- 재사용성 증가: 내부에 상태를 숨기지 않고 외부에서 주입받으면, 컴포저블을 더 다양한 상황에서 재사용할 수 있음
- 단방향 데이터 흐름(One-way Data Flow): UI 상태 관리가 명확해져서 코드가 예측 가능해짐
- 테스트 용이성: 상태를 외부에서 컨트롤할 수 있어 테스트가 쉬워짐
3. State Hoisting 적용 예제
State를 내부에서 관리하는 버전
@Composable
fun NameInput() {
var name by remember { mutableStateOf("") }
TextField(
value = name,
onValueChange = { name = it },
label = { Text("Enter your name") }
)
}
State를 외부로 뺀(State Hoisting 적용한) 버전
@Composable
fun NameInput(
name: String,
onNameChange: (String) -> Unit
) {
TextField(
value = name,
onValueChange = onNameChange,
label = { Text("Enter your name") }
)
}
변화된 점:
- name이라는 상태를 매개변수로 받는다.
- onNameChange라는 콜백을 통해 상태 변경을 외부에 요청한다.
그리고 사용하는 쪽(부모 컴포저블)에서는 이렇게 작성한다.
@Composable
fun NameScreen() {
var name by remember { mutableStateOf("") }
NameInput(
name = name,
onNameChange = { name = it }
)
}
이제 NameInput은 자체 상태를 가지지 않으며, 오직 외부에서 받은 값과 콜백만으로 동작한다.
이 구조가 Compose에서 권장하는 "단방향 데이터 흐름"이다.
4. 언제 State Hoisting을 사용할까?
다음 상황에서는 반드시 State Hoisting을 고려:
- 하위 컴포저블이 독립적으로 재사용되어야 할 때
- 부모 컴포저블이 전체 화면 상태를 제어해야 할 때
- 복잡한 상태 관리가 필요한 경우 (예: ViewModel과 연결할 때)
반면, 단순한 UI 요소나 일회성 컴포저블에서는 내부 상태만으로도 충분할 수 있다.
5. 요약
개념 | 설명 |
---|---|
State | UI를 구성하는 데 필요한 데이터 |
State Hoisting | 상태를 컴포저블 외부(부모)로 끌어올려 관리하는 패턴 |
장점 | 재사용성 증가, 테스트 용이성, 코드 명확성 |
방법 | 값과 이벤트 콜백을 매개변수로 전달 |
6. 마무리
State와 State Hoisting은 Jetpack Compose를 제대로 이해하고 사용하기 위한 핵심 개념이다.
특히 앱이 점점 커질수록, 이 원칙을 지키는 것이 유지보수성과 확장성을 크게 향상시킨다.
Compose를 사용할 때 "상태는 필요한 곳에만 두자" 원칙을 꼭 기억해야한
'Android > Jetpack Compose' 카테고리의 다른 글
[Jetpack Compose] Activity Lifecycle에 맞게 기능 구현 (0) | 2025.04.26 |
---|---|
[Jetpack Compose] 기존 UI방식과 다른 점? (0) | 2025.04.20 |