CompositionLocal


Compose passes data through the composition tree explicitly through means of parameters to composable functions. This is often times the simplest and best way to have data flow through the tree.

Sometimes this model can be cumbersome or break down for data that is needed by lots of components, or when components need to pass data between one another but keep that implementation detail private. For these cases, CompositionLocals can be used as an implicit way to have data flow through a composition.

CompositionLocals by their nature are hierarchical. They make sense when the value of the CompositionLocal needs to be scoped to a particular sub-hierarchy of the composition.

One must create a CompositionLocal instance, which can be referenced by the consumers statically. CompositionLocal instances themselves hold no data, and can be thought of as a type-safe identifier for the data being passed down a tree. CompositionLocal factory functions take a single parameter: a factory to create a default value in cases where a CompositionLocal is used without a Provider. If this is a situation you would rather not handle, you can throw an error in this factory.

import androidx.compose.runtime.compositionLocalOf

val ActiveUser = compositionLocalOf<User> { error("No active user found!") }

Somewhere up the tree, a CompositionLocalProvider component can be used, which provides a value for the CompositionLocal. This would often be at the "root" of a tree, but could be anywhere, and can also be used in multiple places to override the provided value for a sub-tree.

import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider

@Composable
fun App(user: User) {
    CompositionLocalProvider(ActiveUser provides user) { SomeScreen() }
}

Intermediate components do not need to know about the CompositionLocal value, and can have zero dependencies on it. For example, SomeScreen might look like this:

import androidx.compose.runtime.Composable

@Composable
fun SomeScreen() {
    UserPhoto()
}

Finally, a component that wishes to consume the CompositionLocal value can use the current property of the CompositionLocal key which returns the current value of the CompositionLocal, and subscribes the component to changes of it.

import androidx.compose.runtime.Composable

@Composable
fun UserPhoto() {
    val user = ActiveUser.current
    ProfileIcon(src = user.profilePhotoUrl)
}

Summary

Protected constructors

<T : Any?> CompositionLocal(defaultFactory: () -> T)
Cmn

Public properties

T

Return the value provided by the nearest CompositionLocalProvider component that invokes, directly or indirectly, the composable function that uses this property.

Cmn

Protected constructors

CompositionLocal

protected <T : Any?> CompositionLocal(defaultFactory: () -> T)

Public properties

current

val current: T

Return the value provided by the nearest CompositionLocalProvider component that invokes, directly or indirectly, the composable function that uses this property.

import androidx.compose.runtime.Composable

@Composable
fun UserPhoto() {
    val user = ActiveUser.current
    ProfileIcon(src = user.profilePhotoUrl)
}