Android/Jetpack Compose

Android Jetpack Comopse의 CompositionLocal을 이해하고 써보자

chattymin 2024. 3. 26. 11:12
728x90
반응형

왜 나온걸까?

Composable 함수는 Tree구조를 가지고 있다.

이때, 상태(state)는 일반적으로 최상단 노드에 저장이 되어있어야 한다(상태 호이스팅)

상위 트리에서 만든 상태를 하위 트리에서 매개변수로 받는 것이 아닌, 바로 접근할 수 있게 해준다.

 

 

왜 최상단에 저장되어있어야 할까?

컴포넌트들은 상태를 모르는게 좋다. 최상단에서 전달해준 정보를 바탕으로 화면을 나타내는 것이 더 좋은 방법이라고 생각한다. 왜냐하면 상태를 컴포넌트 별로 다 가지고 있다면 이후 추적하는 것도 힘들고, 각각의 상태를 하나씩 참조하며 변경해줘야 하기 때문에 관리하기 더 어려워 진다.

 

그렇다면 상태가 최상단에 있고, 트리 개념으로 아래로 내려가는 UI 구조를 가진다고 했는데 “매번 변수로 state를 내려줘야 하면 너무 귀찮은거 아냐?” 라는 생각이 들 수 있다.

 

그래서 나온 개념이 CompositionLocal이다.

 

 

어떻게 생성할까?

CompositionLocal은 상태를 제공하는 일종의 컨테이너와 같다. CompositionLocal을 만드는 2가지 방법은 다음과 같다.

// StaticProvidableCompositionLocal로 만들기
val localStaticComposition = staticCompositionLocalOf {
    DEFAULT_VALUE
}

// DynamicProvidableCompositionLocal로 만들기
val localDynamicComposition = compositionLocalOf {
	DEFAULT_VALUE
}

 

 

어떻게 하위로 제공할까?

상위 컴포저블 함수부터 하위까지 CompositionLocal을 제공하기 위해 다음과 같이 CompositionLocalProvider를 사용한다.

val LocalErrorComposition = staticCompositionLocalOf<String> {
    "ERROR"
}

@Composable
fun TopComposable() {
    ..
    CompositionLocalProvider(LocalErrorComposition provide "String") {
        TailComposable()
    }
}

@Composable
fun TailComposable() {
    ..
}

CompositionLocalProvider 함수 내부를 살펴보면 알겠지만, CompositionLocal은 1개 이상 제공할 수 있다.

fun CompositionLocalProvider(
    vararg values: ProvidedValue<*>, 
    content: @Composable () -> Unit)

 

 

어떻게 값을 받아올까?

CompositionLocalProvider로 감싼 하위 컴포저블함수들은 이제 CompositionLocal로부터 현재 값을 읽을 수 있다.

@Composable
fun TailComposable() {
    Text(
        modifier = Modifier,
        text = LocalErrorComposition.current
    )
    ...
}

 

 

staticCompositionLocalOf()와 compositionLocalOf()는 뭐가 다를까?

staticCompositionLocalOf() : 자주 변경되지 않는 상태를 저장할 때 이용하면 좋다. 상태가 변경되면 해당 상태가 할당된 노드의 하위 노드를 모두 재구성해야하기 때문이다.

 

compositionLocalOf() : 현재 상태에 접근하는 컴포저블에 대해서만 재구성을 수행한다. 이 함수는 변경이 잦은 상태를 다룰 때 이용해야 한다.

 

이렇게만 설명하면 무조건 compositonLocalOf가 좋아보인다.

 

compositionLocalOf()와 달리 staticCompositionLocalOf() 읽기는 Compose에서 추적하지 않는다.

 

값을 변경하면 컴포지션에서 current 값을 읽는 위치만이 아니라 CompositionLocal이 제공된 content 람다 전체가 재구성된다.

즉, CompositionLocal에 저장한 값이 변경되지 않을 값이라면 성능이 더 좋은staticCompostionLocalOf를 사용하는것이 좋다.

728x90
반응형