개발자의 생활

상태 호이스팅 본문

안드로이드 앱 개발/Compose

상태 호이스팅

Developer성현 2025. 11. 18. 17:01

상태 호이스팅 이란 간단하게 말하면 Composable의 상태를 위로 올리는 개념을 말합니다.

즉 상태를 자식이 관리하지 않고 부모가 관리하도록 만드는 것입니다

 

stateful, stateless

이 두 개는 Composable 가 상태를 관리하는 방법들입니다.

하나씩 자세히 알아보겠습니다.

 

1. stateful

이것은 composable 함수 내부에서 상태를 관리하는 방법입니다.

@Composable
fun CountButton(
    modifier: Modifier
){
    val count = remember { mutableIntStateOf(0) }
    Button(
        onClick = {count.intValue++},
        modifier = modifier
    ) {
        Text(
            text = count.intValue.toString()
        )
    }
}

 

위 코드처럼 자기 자신이 직접 UI와 상태를 관리하는 방식을 stateful이라고 합니다.

 이런 식으로 코드를 작성하게 되면 나중에 해당  composable 함수를 재활용할 수가 없습니다.

 

하지만 무조건 이 방식을 사용하면 안 된다는 것은 아닙니다.

자세한 건 뒤에서 이어서 설명하겠습니다.

 

2. stateless

이 방식이 상태 호이스팅에 사용되는 방식입니다.

@Composable
fun CountButton(
    buttonOnClick: () -> Unit,
    buttonText: String,
    modifier: Modifier
){
    Button(
        onClick = buttonOnClick,
        modifier = modifier
    ) {
        Text(
            text = buttonText
        )
    }
}

 

이렇게 고차함수 형태로 연결해서 상위 Composable 함수에 넘길 수 있도록 만들고 문자열도 파라미터로 받을 수 있도록 만드는 것을 stateless라고 합니다.

 

그러면 이 Composable 함수를 이렇게 사용할 수 있습니다.

@Preview
@Composable
fun CountApp(){
    val count = remember { mutableIntStateOf(0) }
    Scaffold { innerPadding ->
        Box(
            modifier = Modifier
                .padding(innerPadding)
                .fillMaxSize(),
            contentAlignment = Alignment.Center
        ) {
            CountButton(
                buttonOnClick = {
                    count.intValue++
                },
                buttonText = count.intValue.toString(),
                modifier = Modifier
            )
        }
    }
}

 

사실 이러한 구조를 저의는 처음부터 사용하고 있었습니다.

Button 컴포저블 함수를 보면 상태를 상위에서 제어할 수 있도록 Stateless 형태로 되어 있습니다.

 

이렇게 Stateless 형태로 하면 재활용성도 좋아지고 UI 테스트를 하기 편해집니다.

하지만 무조건 모든 Composable 함수를 Stateless로 만들면 안 됩니다.

 

간단한 Composable 트리구조를 통해 이유를 알아보겠습니다.

 

 

모든 Compoable 함수는 결국 하나의 Composable에 모이게 됩니다.

위에서 Root Composable 가 앱을 개발할 때 가장 최상단 컴포저블 함수입니다.

 

만약 모든 Compoable 함수가 Stateless 방식을 사용해서 Root 함수까지 상태를 호이스팅 한다면 Root Composable 함수가 너무 큰 책임을 가지게 됩니다. 또한 이렇게 구성을 할 경우 리컴포지션이 수행될 때 비용이 커지게 됩니다.

 

리컴포지션에 관한 내용은 이전에 다루었지만 간단하게 다시 설명하면 리컴포지션은 상태가 변경된 부분만 재생성한다고 했습니다. 그러면 아무리 트리의 깊이가 깊어지더라도 상관없는 거 아닌가라고 생각할 수 있겠지만 결국 리컴포지션을 하기 위해서는 slot table에 기록되어 있는 정보를 확인하고 상태를 기록하는 위치부터 읽는 부분까지 탐색을 해야 합니다. 그 과정에서 탐색할 Composable 이 많다면 비용이 증가하게 됩니다.

 

그러면 어디까지 상태를 호이스팅 해야 할까요?

명확한 정답은 없겠지만 재활용성을 높이면서도 리컴포지션 비용이 증가하지 않도록 하는 것이 좋겠습니다.

너무 당연한 이야기를 했네요...

 

위 트리구조 이미지로 예시를 들어보면 Text 와 Button 들은 Sub1, 2, 3 까지 상태를 호이스팅 하고 Sub1, 2, 3 에서 상태를 관리하게 되면 Sub1, 2, 3 은 Stateful 이 되는것이고 Text 와 Button 들은 Stateless 가 되는것 입니다.


이상으로 상태 호이스팅 과 stateful, stateless 개념을 알아보았습니다.

끝까지 읽어주셔서 감사드립니다.

'안드로이드 앱 개발 > Compose' 카테고리의 다른 글

리컴포지션(ReComposition)  (0) 2025.11.14