✅ State Hoisting(상태 호이스팅)이란?
컴포저블 함수 내부에서 상태를 직접 관리하는 대신, 상위 컴포저블로 상태를 끌어올려(State Lift) 관리하는 패턴을 의미합니다.
📌 왜 State Hoisting을 사용할까?
- 재사용성 증가: 상태를 특정 컴포넌트에 묶지 않고, 상위에서 관리하면 여러 하위 컴포넌트에서 공유 가능
- 단방향 데이터 흐름 유지: 데이터 흐름이 예측 가능하고 유지보수 쉬워짐
- 컴포저블의 책임 분리: UI 컴포저블은 UI만 담당하고, 상태 관리는 상위에서 담당
🚀 예제: State Hoisting 적용 전 vs 후
❌ 상태를 내부에서 관리하는 잘못된 예시
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) } // 내부에서 직접 상태 관리
Column {
Text("Count: $count")
Button(onClick = { count++ }) {
Text("Increase")
}
}
}
- Counter 내부에서 상태를 직접 관리하기 때문에 외부에서 제어할 수 없음
- 다른 UI에서 count 값을 변경하고 싶다면 어려움 발생
✅ State Hoisting 적용한 올바른 예시
@Composable
fun Counter(count: Int, onIncrement: () -> Unit) {
Column {
Text("Count: $count")
Button(onClick = onIncrement) { // 상태 변경을 상위에서 처리
Text("Increase")
}
}
}
@Composable
fun CounterApp() {
var count by remember { mutableStateOf(0) } // 상위에서 상태 관리
Counter(count = count, onIncrement = { count++ }) // 하위에 상태 전달
}
- Counter 컴포저블이 직접 count를 관리하지 않고, 외부에서 상태를 받음
- CounterApp에서 count 상태를 관리하고, 변경 로직(onIncrement)도 여기서 처리
- 다른 컴포넌트에서도 count를 공유 가능
🎯 State Hoisting 패턴
State Hoisting은 보통 두 개의 매개변수로 표현됩니다.
- 상태 변수 (value)
- 상태를 변경하는 콜백 함수 (onValueChange)
✅ State Hoisting 일반적인 구조
@Composable
fun SomeComponent(value: String, onValueChange: (String) -> Unit) {
TextField(value = value, onValueChange = onValueChange)
}
@Composable
fun ParentComponent() {
var text by remember { mutableStateOf("") }
SomeComponent(value = text, onValueChange = { text = it }) // 상태를 부모가 관리
}
- SomeComponent는 직접 value를 관리하지 않음
- ParentComponent에서 상태를 소유하고 onValueChange를 통해 하위 컴포넌트에 전달
🎯 State Hoisting이 필요한 상황
✅ 여러 컴포넌트에서 같은 상태를 공유해야 할 때
✅ 상태 변경 로직을 한 곳에서 관리하고 싶을 때
✅ UI 컴포넌트가 상태 관리 없이 재사용 가능해야 할 때
🚀 정리
State Hoisting은 컴포저블 내부에서 상태를 직접 관리하는 것이 아니라, 상위 컴포저블로 끌어올려 관리하는 패턴이다.
이를 통해 재사용성, 유지보수성, 예측 가능성이 향상되며, 단방향 데이터 흐름(Unidirectional Data Flow, UDF)을 유지할 수 있다! 🚀
✔ 하위 컴포저블은 UI만 담당하고, 상태 관리는 상위에서! 🔥
✅ State Hoisting과 Recomposition(재구성)의 관계
State Hoisting(상태 호이스팅)과 Recomposition(재구성)은 Jetpack Compose의 상태 관리와 성능 최적화에서 중요한 개념입니다.
간단히 말해, State Hoisting을 올바르게 사용하면 불필요한 Recomposition을 줄이고 앱 성능을 향상시킬 수 있습니다.
🎯 Recomposition(재구성)이란?
- Compose에서는 상태가 변경되면 UI를 다시 그리는 과정을 Recomposition(재구성)이라고 함.
- 예를 들어, mutableStateOf() 값을 변경하면, 이를 참조하는 @Composable 함수가 다시 실행됨.
- 하지만 불필요한 Recomposition이 발생하면 성능 저하가 발생할 수 있음.
🚀 State Hoisting이 Recomposition을 줄이는 이유
State Hoisting은 상태를 상위 컴포넌트에서 관리하는 방식이므로, 불필요한 UI 업데이트를 방지하는 효과가 있음.
❌ State Hoisting을 사용하지 않은 경우 (비효율적인 Recomposition 발생)
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) } // 내부에서 직접 상태 관리
Column {
Text("Count: $count")
Button(onClick = { count++ }) {
Text("Increase")
}
}
}
- count가 변경될 때마다 Counter 함수 전체가 Recomposition됨
- 하지만 Text("Increase")는 상태와 관계없는 UI 요소인데도 불필요하게 다시 그려짐
- 해결책? → State Hoisting을 활용하여 최소한의 Recomposition 유지
✅ State Hoisting을 적용한 경우 (Recomposition 최적화)
@Composable
fun Counter(count: Int, onIncrement: () -> Unit) {
Column {
Text("Count: $count") // count 변경 시 여기는 재구성됨
Button(onClick = onIncrement) {
Text("Increase") // ❌ 이 부분은 Recomposition 되지 않음!
}
}
}
@Composable
fun CounterApp() {
var count by remember { mutableStateOf(0) } // 상위에서 상태 관리
Counter(count = count, onIncrement = { count++ }) // 하위에 상태 전달
}
- Counter의 내부 UI(버튼, 레이아웃)는 그대로 유지되고, Text("Count: $count") 부분만 재구성됨!
- count 값이 변경될 때, Button은 Recomposition 되지 않아서 성능 최적화 가능!
🎯 State Hoisting을 통한 Recomposition 최적화 원칙
- 상태를 필요하지 않은 곳에서 관리하지 않는다.
- UI가 필요로 하는 최소한의 범위에서만 Recomposition을 발생시키기 위해 상위에서 관리
- Compose의 데이터 흐름을 유지 (Unidirectional Data Flow, UDF)
- 하위 컴포저블은 상태를 직접 관리하지 않고, 매개변수로 전달받아 UI만 담당
- 상태를 변경하는 로직은 상위 컴포저블에서 처리
- 컴포넌트를 작게 나누어 Recomposition 최소화
- Compose는 변경된 상태만 감지하여 업데이트하지만, 컴포넌트가 크면 불필요한 부분까지 다시 그림
- 따라서 UI 요소를 재사용 가능한 작은 컴포넌트로 나누면 불필요한 Recomposition을 줄일 수 있음!
🚀 결론
✅ State Hoisting을 올바르게 사용하면, 불필요한 Recomposition을 줄이고 성능을 최적화할 수 있음!
✅ 하위 컴포넌트는 UI만 담당하고, 상태 관리는 상위에서!
✅ Compose의 Recomposition 원리를 이해하고 최소한의 UI 업데이트를 유지하는 것이 중요! 🚀
'Android' 카테고리의 다른 글
[Android] SMS Retriever 못 받아오는 오류 (0) | 2024.12.19 |
---|---|
[Android] 앱 삭제 시에도 SharedPreference가 남아있는 현상 (0) | 2024.11.21 |
[Android] 안드로이드 앱 비동기 처리 및 interceptor (1) | 2024.11.20 |
[Android] FLAG_ACTIVITY_SINGLE_TOP 와 FLAG_ACTIVITY_CLEAR_TOP 차이점 (0) | 2024.11.19 |
[Android] gradle를 활용한 firebase App distribution 배포 후 slack 알람 연동 (0) | 2024.11.17 |