> `staticCompositionLocalOf`: Unlike `compositi...
# compose
m
`staticCompositionLocalOf`: Unlike
compositionLocalOf
, reads of a `staticCompositionLocalOf`are not tracked by Compose. Changing the value causes the entirety of the
content
lambda where the
CompositionLocal
is provided to be recomposed, instead of just the places where the `current`value is read in the Composition.
I don’t understand this explanation. I know that… •
CompositionLocal<T>
is subclassed by
ProvidableCompositionLocal<T>
• Subclasses of
ProvidableCompositionLocal<T>
are instantiated by the factory functions mentioned above, and override the
defaultProvidedValue(value: T): ProvidedValue<T>
method. ◦ Instances by
compositionLocalOf
pass
mutationPolicy = this.policy
and
isDynamic = true
to the
ProvidedValue<T>
constructor. ◦ Instances by
staticCompositionLocalOf
pass
mutationPolicy = null
and
isDynamic = false
to the
ProvidedValue<T>
constructor. •
.provides(value: T): ProvidedValue<T>
calls and returns
.defaultProvidedValue(value)
. The returned
ProvidedValue<T>
is passed to
ProvidableCompositionLocal<T>.valueHolderOf(value: ProvidedValue<T>): ValueHolder<T>
. ◦
interface ValueHolder<T>
is implemented by
DynamicValueHolder<T>
,
StaticValueHolder<T>
, etc. ◦ Instances by
compositionLocalOf
return a
ProvidedValue<T>
that’s converted to a
DynamicValueHolder<T>(val state: MutableState<T>)
. ◦ Instances by
staticCompositionLocalOf
return a
ProvidedValue<T>
that’s converted to a
StaticValueHolder<T>(val value: T)
. I also know that the conversion happens when the current
Composer
starts a provider. So it makes sense that instances by
compositionLocalOf
would be backed by state objects tracked by the snapshot system.
Changing the value causes the entirety of the
content
lambda where the
CompositionLocal
is provided to be recomposed
But how can this be true in the case of instances by
staticCompositionLocalOf
? They’re not backed by state objects and mutating them wouldn’t invalidate any compositions as a result.
a
The
staticCompositionLocalOf
s are backed by a
StaticValueHolder
which doesn't have a mutable state, unlike the
DynamicValueHolder
that backs
compositionLocalOf
, which does have a mutable state. I think the best way to think about it is starting from a world that only has static composition locals: if any composition local changes, or if you remove a composition local or provide a new one, then everything needs to recompose. This isn't because a state object changed, it's because something specific to the composition changed. A "normal"
compositionLocalOf
is more of a special case: since it is itself backed by mutable state, if that value updates internally, then needing to update "everything" can be skipped since the internally mutable change can be observed directly
m
@Alex Vanyo I still don’t get it. Can I see an example where which between
compositionLocalOf
and
staticCompositionLocalOf
I use makes a difference please? Why is a mutable state even remembered for instances by the first factory? How do you even write to the mutable state?
z
You write to it by passing a new value to
CompositionLocalProvider
(ie the api for mutating a local is the same for both)
m
@Zach Klippenstein (he/him) [MOD] I see, thanks!
I have a followup. I know that writing a different value to a mutable snapshot state invalidates all recompose scopes that read it. But no mutable snapshot state is remembered for a mapping of a composition local by
staticCompositionLocalOf
. When a
CompositionLocalProvider
is recomposed with a different value for such a local, how does remembering a new
StaticValueHolder(value.effectiveValue)
for it invalidate the recompose scope of the
content
composable?