CompositionLocal

일반적으로 Compose의 상태는 위에서 아래로 흐르는 단방향 데이터 흐름 패턴을 사용한다. 그러나 자주 널리 사용되는 데이터를 단방향 데이터 흐름을 적용하면 번거로울 수 있다.

@Composable  
fun MyApp() {  
    // Theme information tends to be defined near the root of the application  
    val colors =   
}  
  
// Some composable deep in the hierarchy  
@Composable  
fun SomeTextLabel(labelText: String) {  
    Text(  
        text = labelText,  
        color = // ← need to access colors here  
    )  
}

CompositionLocal은 Composition을 통해 데이터를 암시적으로 전달한다.

  
@Composable  
fun MyApp() {  
    // Provides a Theme whose values are propagated down its `content`  
    MaterialTheme {  
        // New values for colors, typography, and shapes are available  
        // in MaterialTheme's content lambda.  
        // ... content here ...    }  
}  
  
// Some composable deep in the hierarchy of MaterialTheme  
@Composable  
fun SomeTextLabel(labelText: String) {  
    Text(  
        text = labelText,  
        // `primary` is obtained from MaterialTheme's  
        // LocalColors CompositionLocal
        color = MaterialTheme.colors.primary  
    )  
}

CompositionLocal의 current 값은 Composition의 상위 Composable에서 제공한 부분의 가장 가까운 값에 대응한다.

CompositionLocal에 값을 제공하기 위해서는 provides라는 infix 함수를 이용한다.

@Composable  
fun CompositionLocalExample() {  
    MaterialTheme { // MaterialTheme sets ContentAlpha.high as default  
        Column {  
            Text("Uses MaterialTheme's provided alpha")  
            CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {  
                Text("Medium value provided for LocalContentAlpha")  
                Text("This Text also uses the medium value")  
                CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {  
                    DescendantExample()  
                }  
            }
        }   
    }
}  
  
@Composable  
fun DescendantExample() {  
    // CompositionLocalProviders also work across composable functions  
    Text("This Text uses the disabled alpha now")  
}

CompositionLocal은 암시적으로 Composition에 값을 전달하기 때문에 남발하면 Composable의 추론이 어려울 수 있으며 예상치 못한 결과를 일으킬 수 있다. 또한 CompositionLocal의 값은 Composition의 어떤 부분에서도 변경 가능하기 때문에 명확한 정보 소스를 찾기 어렵다.

CompositionLocal 사용 여부 결정

  • 적절한 기본값이 필요: 기본값이 없으면 CompositionLocal에 값이 제공되지 않을 수 있는 문제가 생긴다.
  • 모든 하위 요소에서 사용할 때 적합

CompositionLocal 만들기

  • compositionLocalOf : 값을 변경하면 current 값을 읽는 콘텐츠의 재구성
  • staticCompositionLocalOf: Compose에서 값을 추적하지 않음. 따라서 값을 변경하면 CompositionLocal이 적용된 content 람다 전체가 재구성 CompositionLocal의 값이 자주 변경되지 않을 것이라는게 확실할 경우 staticCompositionLocalOf를 사용하여 성능 이점을 얻을 수 있다.
// LocalElevations.kt file  
  
data class Elevations(val card: Dp = 0.dp, val default: Dp = 0.dp)  
  
// Define a CompositionLocal global object with a default  
// This instance can be accessed by all composables in the app  
val LocalElevations = compositionLocalOf { Elevations() }

CompositionLocal에 값 제공

CompositionLocalProvider는 주어진 계층 구조의 CompositionLocal에 값을 바인딩한다.

// MyActivity.kt file  
  
class MyActivity : ComponentActivity() {  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
  
        setContent {  
            // Calculate elevations based on the system theme  
            val elevations = if (isSystemInDarkTheme()) {  
                Elevations(card = 1.dp, default = 1.dp)  
            } else {  
                Elevations(card = 0.dp, default = 0.dp)  
            }  
  
            // Bind elevation as the value for LocalElevations  
            CompositionLocalProvider(LocalElevations provides elevations) {  
                // ... Content goes here ...  
                // This part of Composition will see the `elevations` instance
                // when accessing LocalElevations.current
	        }  
        }
    }  
}

CompositionLocal 사용

@Composable  
fun SomeComposable() {  
    // Access the globally defined LocalElevations variable to get the  
    // current Elevations in this part of the Composition
    Card(elevation = LocalElevations.current.card) {  
        // Content  
    }  
}

© 2021. All rights reserved.

Powered by Hydejack v9.1.6