In compose version 0.3.0-build143 the onDispose fu...
# compose-desktop
t
In compose version 0.3.0-build143 the onDispose function is replaced by DisposableEffect where a key is required. But in my use case i just want to do some cleanups when the composable is removed from the view tree. How can i implement this with the new API?
j
Can you elaborate on the type of cleanup you want to perform? It is our expectation that a
DisposableEffect
without a key would be rare, and would love to see details about any counterexample. With regards to your specific question though, I believe you can just pass in
Unit
as the key parameter, which will satisfy the compiler.
The fact that passing
Unit
looks awkward is very intentional, goal is to get a code reviewer to be like 😬 (and hopefully ask questions) when they see it.
t
I do have a custom navigation framework. And a composable is used as root element for the navigation. Than when the app navigates to different screens a backstack is build up. When the root composable is disposed i want to reset the backstack.
btw i also use onCommit(key) in my app without needs for a dispose function. Do i have to use DisposableEffect with an empty onDispose implementation? Or is there any other alternative?
a
For the first one, it sounds like the back stack object being reset on disposal is an appropriate key
for onCommit, it depends on what you're doing with it. If you're applying changes to other objects, use
SideEffect
.
For these use cases you shouldn't need the key; compose shouldn't be responsible for idempotence of set operations on your objects, the objects themselves should do that.
t
I want to code a transition effect. So when the key changes i need to update the state of the transition object.
And i do not want to create a new Transition object because i need the old state
other wise i could use just remember with keys
Code is like this:
Copy code
val ts = remember { CrosstransitionState<SavedStateData<T>>() }
DisposableEffect(transition) {
    ts.newTarget(transition.data)
    ...
    ts.scope?.invalidate()
    onDispose {

    }
}
a
seems like what you're looking for is:
Copy code
val ts = remember { ... }
SideEffect {
  ts.target = transition.data
}
setting
target
should skip if the new value is equal or invalidate as necessary
t
Is the code inside SideEffect is executed again if the MutableState of the variable transition is changed?
a
It is executed only after the current recomposition succeeds
every time that composable is recomposed
t
Ok but than this code will not work.
a
If you were using the
onCommit
to observe a snapshot state object for changes to run some code when it does change, then you've encountered the antipattern that this API change was intended to break/make very awkward 🙂
the reason not to use
onCommit
that way is that it forces recomposition of its surroundings to dispatch an event callback, and it does so by waiting for a composition frame.
Chances are there's a 1-frame delay before your work actually starts that doesn't need to be there as a result too.
The way to think of this is that you want to independently observe changes to snapshot state, and make sure that those changes feed into later recomposition only if needed
t
Ok i see.
a
one way to do this is with `snapshotFlow`:
Copy code
val ts = remember { ... }
LaunchedEffect(ts) {
  snapshotFlow { transition }.collect { newTransitionValue ->
    ts.newTarget(newTransitionValue.data)
    // ...
  }
}
this lets you observe changes independent of recomposition, but still manage the scope of that observation within your composable.
t
I think i do have this code snippets from older implementations of Crossfade or other transition effect.
a
probably 🙂 we learned many of the antipatterns and why they're antipatterns the hard way in our own codebase
not all of them have been addressed yet
t
Ok i think i could do it than this way:
Copy code
val ts = remember { ... }
if (ts.target != transition.data) {
    ts.target = transition.data
}
this would recompose the composable when transition is changed. And this is exactly what i want.
In Crossfade it is also implemented like that
a
So long as `ts.target`'s set function has no other side effects beyond setting other snapshot state, that can work fine. If it does, you might be in for some correctness problems in the not too distant future, since composition can fail and you don't want lingering side effects that we can't roll back by discarding the current mutable snapshot in progress.
t
ok thx. I will try to fix my code 😄