본문 바로가기
프로그래밍/Jetpack Compose

[Jetpack Compose] State Hoisting (상태 끌어올리기) 를 알아보자

by dev_gyu 2024. 9. 24.
728x90

Stateful 과 Stateless 의 차이에 대해 알지 못하고 있다면 아래 링크를 통해 참고 바랍니다.

https://dev-oh-gyu.tistory.com/entry/Jetpack-Compose-Stateful-Stateless-%EA%B0%80-%EB%AD%98%EA%B9%8C

 

[Compose] Stateful, Stateless 가 뭘까?

이전 글 - [Jetpack Compose] 변수 선언하기 [Jetpack Compose] 변수 선언하기 (remember, rememberSaveable 등)Jetpack Compose 에서는 변수를 선언할 때 리컴포지션이라는 특성과 함께 상태 관리를 위해 remember 라는

dev-oh-gyu.tistory.com

 


 

과거 포스트를 통해 우리는 리컴포지션을 최소화하기 위해서는 Composable 을 최대한 Stateless 하게 유지하는 것이 좋다는 것을 알게 되었다.

 

하지만 Compose 를 사용하기 위해서는 객체를 Current Composer 에 캐싱을 해야하므로 필연적으로 Stateful Composable 은 만들어질 수 밖에 없다.

 

Stateful Composable 을 매번 만들지 않고 하나 혹은 소수의 Composable 로 유지하게 된다면 메모리 상에서도, 테스트 코드 작성에도 매우 효율적일 것인데, Stateless 를 최대한 유지하려면 어떤 방법을 사용해야할까?

 

State Hosting (상태 호이스팅)

이럴 때 사용되는 기법이 바로 State Hoisting 이다.

State Hoisting 은 상태를 끌어올린다 라는 의미를 가지고 있는데 다음과 같은 특징을 지니고 있다

1. 자식 컴포저블이 가지고 있는 State 를 부모 컴포저블 (가급적이면 공통된 성격을 가진 곳) 로 끌어올려 자식을 Stateless 상태로 만들어준다.
2. 상태 호이스팅을 사용하면 자식 컴포저블이 Stateless 한 상태로 유지되므로 Test Code 및 코드 재사용에 용이해진다.

 


우리가 컴포지션 트리를 구성할때 (Composable 을 만들때) 어떤 Composable 의 Text Composable 이 버튼을 클릭할 때마다 변하는 Number 라는 값에 의존한다고 생각해보자.

 

@Composable
fun TestComposable(){
    var isUser by remember { mutableStateOf(True) }

    Text(text = isUser.toString())
    Button(onClick = { isUser = isUser.not() }){}
}

 

이 컴포저블은 유저인지 확인하는 객체 isUser 를 가지고 있으면서, 이 결과값을 Text 로 표시한다.

현재의 값은 default True 로 설정되어 있지만 만약 다른 화면에서 이 함수를 재사용하면서 default 값을 False 로 처리하고 싶은 경우 위의 함수는 재사용할 수 없다.

내부적으로 State 가 선언되어 재설정을 해줄 수 없기 때문이다.

 

그렇기에 우리는 State Hoisting 을 통해 상태 관리를 상위로 넘겨주고 UI 재사용에 쉽게 Stateless 로 바꿔줄 것이다.

 

@Composable
fun ParentComposable1(){
    var isUser by remember { mutableStateOf(true) }

    TestComposable(
        isUser = isUser,
        onClick = { isUser = isUser.not() }
    )
}

@Composable
fun ParentComposable2(){
    var isUser by remember { mutableStateOf(false) }

    TestComposable(
        isUser = isUser,
        onClick = { isUser = isUser.not() }
    )
}

@Composable
fun TestComposable(isUser: Boolean, onClick: () -> Unit){
    Text(text = isUser.toString())
    Button(onClick = onClick){}
}

 

위와 같이 상태를 끌어올려준다면 UI 재사용 및 추후 테스트 코드 작성 시에도 많은 도움이 생기게 된다 !

 
 
728x90