본문 바로가기
Android/Compose

[Android] Stateful, Stateless 컴포저블 차이와 상태 호이스팅

by LoseyKim 2024. 9. 4.

Jetpack Compose에서 UI를 구성할 때, 컴포저블 함수는 크게 두 가지 유형으로 나눌 수 있어요: Stateful 컴포저블Stateless 컴포저블이에요. 이 두 가지 유형은 상태를 어떻게 관리하고, 어디에 위치시킬지에 따라 구분됩니다. 또한, 상태 호이스팅은 이 두 유형의 컴포저블 간의 상호작용을 효율적으로 관리하기 위한 중요한 개념이에요.


1. Stateful 컴포저블이란?

Stateful 컴포저블은 내부에 상태를 가지고 있으며, 이 상태는 시간이 지나면서 변할 수 있어요. 이 컴포저블은 자체적으로 상태를 관리하고, 상태의 변화에 따라 UI를 업데이트합니다. Stateful 컴포저블은 주로 간단한 상태 관리가 필요한 UI 요소에서 사용돼요.

예시

@Composable
fun StatefulCounter() {
    var count by remember { mutableStateOf(0) }  // 내부 상태
    Button(onClick = { count++ }) {  // 상태 변화에 따른 UI 업데이트
        Text(text = "Count: $count")
    }
}

위 코드에서 `StatefulCounter`는 `count`라는 상태를 내부에 가지고 있어요. 버튼을 클릭할 때마다 `count`가 증가하며, 이에 따라 화면에 표시되는 텍스트가 업데이트됩니다.


2. Stateless 컴포저블이란?

Stateless 컴포저블은 자체적으로 상태를 관리하지 않는 컴포저블이에요. 대신, 외부에서 전달된 상태를 받아 UI를 구성합니다. Stateless 컴포저블은 상태를 소유하지 않기 때문에, 재사용성이 높고, 여러 곳에서 동일한 컴포저블을 사용하면서도 각기 다른 상태를 적용할 수 있어요.

예시

@Composable
fun Greeting(name: String) {
    Text(text = "Hello, $name!")  // 외부에서 전달된 상태 사용
}

`Greeting` 컴포저블은 외부에서 `name`이라는 문자열을 받아서 UI를 그립니다. 이 컴포저블 자체는 상태를 관리하지 않으며, 오직 전달된 데이터를 화면에 표시하는 역할만 해요.


3. 상태 호이스팅의 필요성

상태 호이스팅(State Hoisting)은 상태를 소유할 위치를 결정하는 중요한 설계 패턴이에요. 상태 호이스팅이 필요한 경우는 다음과 같아요.

  • 여러 컴포저블 함수에서 상태를 공유해야 하는 경우: 상태를 하위 컴포저블들이 공유해야 할 때, 이 상태를 상위 컴포저블로 끌어올려서(호이스팅) 관리하는 것이 좋아요. 이렇게 하면 여러 하위 컴포저블이 동일한 상태를 참조할 수 있어요.
  • 재사용 가능한 Stateless 컴포저블을 만들고자 할 때: Stateless 컴포저블을 만들어 재사용성을 높이고, 상태 관리는 상위 컴포저블에서 담당하도록 하면, 동일한 컴포저블을 다양한 상황에서 재사용할 수 있어요.

예시

@Composable
fun ParentComposable() {
    var count by remember { mutableStateOf(0) }  // 상태를 상위 컴포저블로 호이스팅

    Column {
        StatefulCounter(count, onIncrement = { count++ })  // 상태와 상태 변경 함수를 전달
        StatelessCounterDisplay(count)  // 동일한 상태를 공유
    }
}

@Composable
fun StatefulCounter(count: Int, onIncrement: () -> Unit) {
    Button(onClick = onIncrement) {
        Text(text = "Count: $count")
    }
}

@Composable
fun StatelessCounterDisplay(count: Int) {
    Text(text = "Current Count: $count")
}

위 예시에서, `count` 상태는 `ParentComposable`에서 관리되며, 이 상태는 `StatefulCounter`와 `StatelessCounterDisplay` 두 컴포저블에 전달돼요. 이렇게 하면 `count`라는 상태를 여러 컴포저블이 공유하면서도, 상태 관리 로직을 상위 컴포저블에 집중시킬 수 있어요.


요약

Stateful 컴포저블은 상태를 관리하는 데 유용하지만, 재사용성이 떨어질 수 있어요. 반면, Stateless 컴포저블은 재사용성이 높지만, 상태를 외부에서 관리해야 해요. 따라서, 상황에 맞게 두 가지 유형의 컴포저블을 적절히 사용하고, 상태 호이스팅을 통해 상태 관리를 최적화하는 것이 중요해요.