I'm trying to understand why this code doesn't wor...
# compose
b
I'm trying to understand why this code doesn't work as expected without
.copy()
in `remember { colors.copy() }`:
Copy code
@Composable
fun ProvideAppColors(
    colors: AppColors,
    content: @Composable () -> Unit
) {
    val appColors = remember { colors.copy() }.apply { update(colors) }

    CompositionLocalProvider(
    LocalAppColors provides appColors,
    content = content)
}
Without
.copy()
, it only works for the first change in state. Full code: https://gist.github.com/alashow/e67a75d662a13ce5529317bde3e241c2
s
In general - don't remember your parameters as they're owned by the caller. Looking more
b
I actually don't know why that part was needed. Took it from here when trying to implement custom colors: https://github.com/android/compose-samples/blob/fd7a5bb94808200df9fb8ccb8e17cb352c[…]tsnack/app/src/main/java/com/example/jetsnack/ui/theme/Theme.kt
s
Ah I'll open a bug there
So looking at your code here,
AppTheme
is the source of truth about the AppColors
Given the structure, you can either remember it there, or just reference LightAppColors/DarkAppColors directly without any remember
I'd personally just not use remember here at all and make AppTheme responsible for transforming
darkTheme: Boolean
into a
AppColors
every time it recomposes
b
so apparently without remembering colors in ProvideAppColors,
LocalAppColors.current
doesn't get updated
s
Oh interesting, tbh I'm not 100% familiar with the internal workings of CompositionLocals so I'm not sure how to advise there cc @Leland Richardson [G] @Adam Powell
Actually may be related to @Stable too, they're the right people to answer that
a
Actually there was a bug in
MaterialTheme
caused by removing
.copy()
.
s
Ah yes this makes sense
As to why this pattern is everywhere is another question 🙂
Ah I see, this looks like an optimization to avoid changing the Colors object, which avoids extra recompositions. Basically, by using
remember
without a key, there will only ever be one
AppColors
object referenced lower in the tree, and the colors which are represented by
MutableState
will be independently observed
This would avoid situations where changing one color would recompose the entire application due to unrelated reads
If you don't put the
.copy()
in there, then you're mutating the globals, so when you try to update it again it fails. e.g. 1. Provide
DarkAppColors
2. Update
DarkAppColors
to
LightAppColors
3. Update
DarkAppColors
to
DarkAppColors
(which now has the same values as
LightAppColors
)
👍 1