https://kotlinlang.org logo
#compose
Title
# compose
z

Zoltan Demant

11/03/2023, 6:23 AM
Im updating a
MutableState<Boolean>
on every recomposition (in a
SideEffect
). Would using a
LaunchedEffect(value) { mutableState.value = value }
make any difference, given that the value only ever switches between simple true/false? Some more context in 🧵
Looking at `SnapshotMutableStateImpl`: the setter would be invoked on every recomposition and at least get to
next.withCurrent {}
before the equality check comes through; and theres quite a bit of logic happening in there.
Copy code
@Suppress("UNCHECKED_CAST")
override var value: T
    get() = next.readable(this).value
    set(value) = next.withCurrent {
        if (!policy.equivalent(it.value, value)) {
            next.overwritable(this, it) { this.value = value }
        }
    }
Copy code
@PublishedApi
internal fun <T : StateRecord> current(r: T) =
    Snapshot.current.let { snapshot ->
        readable(r, snapshot.id, snapshot.invalid) ?: sync {
            Snapshot.current.let { syncSnapshot ->
                readable(r, syncSnapshot.id, syncSnapshot.invalid)
            }
        } ?: readError()
    }
Also, Im sure both of these approaches are fast. I havent seen any issues as a result of doing this, but Im incorporating this in more and more places as my codebase grows and Id love to know if Im really shooting myself in the foot before I get too deep.
n

natario1

11/03/2023, 7:28 AM
I don’t know about performance, but there’s probably a better solution to achieve what your boolean state is achieving (which I don’t know). SideEffect docs say that you are not supposed to interact with compose-managed state in there.
z

Zoltan Demant

11/03/2023, 8:17 AM
SideEffect docs say that you are not supposed to interact with compose-managed state in there.
I wasnt aware of that, do you have the source for it? I get very broad search results as soon as SideEffect is included 😅
z

Zoltan Demant

11/03/2023, 8:34 AM
Ah yes, I saw that but my interpretation was rather that it was suitable for both external & composition-related side effects? As for my use-case, Im providing a class that handles text formatting through a composition-local; since I want the class to remain the same throughout, Im updating some variables inside of it (this is where the boolean comes into play).
n

natario1

11/03/2023, 8:47 AM
Yeah it doesn’t explicitly say you shouldn’t but it doesn’t mention your use case either - I have never seen anyone using it this way. To me you’re misusing the tool and should go with
LaunchedEffect
instead, keep
SideEffect
for external stuff.
z

Zoltan Demant

11/03/2023, 9:37 AM
Ill do that for now 👍🏽
s

shikasd

11/03/2023, 3:53 PM
So technically
SideEffect
and
LaunchedEffect
are the same kinda thing, they just have different execution semantics. If you can use
SideEffect
/
DisposableEffect
, they are much cheaper, as they don't create coroutine scope. It is however a bit concerning that you are mutating a state in effects, this has potential of creating recomposition loops. Why do you need this?
z

Zoltan Demant

11/04/2023, 6:42 AM
Gotcha! Ill share some more details about my case, perhaps it will make sense then - or not! Either way, Id love some feedback. Ultimately I have a Localizer interface that is part of my multiplatform code, it has several functions with defaults from a config: fun format(value: X, someBool: Boolean = config.someBool). The config is just a val config, but config.someBool is a value backed by a mutableState because Id like the relevant UI to recompose whenever it changes. In Android, I simply create it in my activity and pass it to LocalLocalizer; which my entire app then uses to format text. My root feature loads user preferences, which holds the "new" value for the config - I pass these to my composable, and it updates the localizer.config.someBool (in a SideEffect, in a separate composable with the boolean as only input so that it doesnt run more often than required). I realize that I could approach this in a number of other ways. Previously Ive passed in Flow<Config> to my Localizer fx, I could also update it from my feature (kind of like doing it from a viewmodel). I really like that its currently "only" part of compose & UI.
4 Views