#state hoisting Android Developer 공식 문서
=> https://developer.android.com/jetpack/compose/state-hoisting?hl=ko
-StateHoisting은 디자인 패턴 중 하나로서 상태를 하위 컴포저블에서 최상위 컴포저블 또는 공통 부모 수준의 컴포저블로 끌어올려서 하위 컴포저블 간에 상태를 공유 할 수 있게 해주고 , 테스트를 용이하게 해주는 역할을 한다.
-최상위 컴포저블이라고 해서 무조건 첫번째를 의미하는 것은 아니다. 스테이트 호이스팅을 적용 할 때에는 상태가 소비되는 컴포저블들의 가장 인접한 상위 레벨에 상태가 위치해야 된다는 것을 의미한다.
-스테이트 호이스팅을 사용하면 상태를 가지고 있는 컴포저블은 상태를 직접 관리하는 대신에 , 상태를 가지고 있지 않은 하위 컴포저블은 상태를 읽고 업데이트하는 콜백 함수를 인자로 받아서 사용한다.
-즉, 호이스팅을 적용하게 된다면 , [1. state를 가지고 있는 컴포저블 함수]와 [2. state를 가지고 있지않는 컴포저블 함수] 이렇게 분리가 된다. 1번 함수에서는 state를 코드 내부에서 선언해주고 그 코드 내부에 2번 함수를 넣어서 사용하면 된다.
-원리는 2번 함수에 파라미터에 들어가서 활용했어야 할 state를 1번함수의 {} 코드 블락 내부에 선언해줌으로서 2번 함수는 굳이 파라미터로 state를 받아서 사용 할 필요가 없다는 의미이다. 이렇게 하면 2번 함수의 parameter의 콜백 함수에서 state를 받아서 활용하면 된다.
-UI 로직에서의 상태 호이스팅 : UI 로직에서 상태 호이스팅을 적용하면 , 상태를 UI 컴포저블의 외부로 이동시켜 상위 컴포저블에서 관리하도록 하고 하위 컴포저블은 콜백 함수로 스태이트를 받아서 관리를 하면 하위 컴포저블은 무상태가 되어서 재사용성과 테스트 용이성이 높아진다.
-비즈니스 로직에서의 상태 호이스팅 : 비즈니스 로직은 애플리케이션의 핵심 기능과 관련된 로직을 의미하는데 , 비즈니스 로직에서 상태 호이스팅을 적용 할 때에는 , 상태를 더 높은 수준인 ViewModel로 이동시켜서 비즈니스 로직과 UI 로직을 아예 분리시켜서 비즈니스 로직의 상태와 UI 로직의 상태를 분리시켜서 독립적으로 관리 할 수 있다.
-결론적으로 상태 호이스팅을 적용하면, UI로직과 비즈니스 로직이 명확하게 분리되어서 각각의 책임이 더 명확해지면서 UI 컴포저블은 단순히 데이터를 화면에 띄우고 사용자와 상호작용하는 데 집중 할 수 있고 , 비즈니스 로직은 앱의 핵심 기능을 실행하는데 집중 할 수 있다는 장점이 있다.
@Composable
fun StateHoistingExCode() {
> 상태를 최상위 레벨로 호이스팅
var counterState by remember { mutableStateOf(0) }
> 상태를 하위 컴포저블로 전달
Counter(
count = counterState,
updateCount = { newCount ->
counterState = newCount
}
)
}
@Composable
fun Counter(count: Int, updateCount: (Int) -> Unit) {
Button(onClick = { updateCount(count + 1) }) {
Text("Clicked $count times")
}
}
>ViewModel 클래스
class ExampleViewModel : ViewModel() {
> LiveData를 사용하여 UI 상태 관리
private val _state = MutableLiveData<ExampleState>()
val state: LiveData<ExampleState> = _state
> 비즈니스 로직을 실행하는 함수
fun performBusinessLogic() {
> 비즈니스 로직 결과에 따라 상태 업데이트
_state.value = ExampleState(result = "짜잔")
}
}
> UI 상태를 저장하는 데이터 클래스
data class ExampleState(val result: String)
> 컴포저블에서 ViewModel 사용
@Composable
fun ExampleScreen(viewModel: ExampleViewModel = ExampleViewModel()) {
val state by viewModel.state.observeAsState()
> 실제 UI 업데이트
Column{
Text(text = state?.result ?: "")
Button(onClick = { viewModel.performBusinessLogic() }) {
Text("비즈니스 로직 실행")
}
}
}