vivid-money/elmslie

Research providing Effects from State for Jetpack Compose

Closed this issue · 7 comments

Maybe we can make State to inherence from class ComposableState with field UiEffects. And allow storing Composable side-effects inside this new field. In this case inside reducer, we will have our usual handle effects field for system effects, and this UIEffect field of State for Composable Ui Effects

The main problem with this approach is duplicating Effects after process death. Effect will be saved in state and dispatched you ui the second time after store recreation since there's no mechanism to remove it from state after it was displayed

rcmkt commented

Why don't you use the following code in the sample?

The snippet inside the root 'setContent':

DisposableEffect(this) {
          val disposable = store.effects.subscribe {
                handleEffect(it)
           }
            onDispose { disposable.dispose() }
}
// UI Composable...

There is no need to have EffectWithKey class, and also I think it's not a good practice to have effects in the state. Like at all)
With Compose the navigation is the only kind of Effect which is still in the game. Because outside the Composable tree you do not have the access to the UI so many effects we used before are useless now except the navigation.

The main point is that the current solution supports accessing effects inside @composable functions. For example it's required for displaying Snackbars with errors.

I don't think that the solution that you suggest would work. The lambda inside DisposableEffect is not @composable, so it won't be possible to show a Snackbar with an error. Now it's done inside PagingScreen#Error method.

If you take a look the source code of subscribeAsState you will see that it's almost the same:

val state = remember { mutableStateOf(initial) }
DisposableEffect(this) {
    val disposable = subscribe {
        state.value = it
    }
    onDispose { disposable.dispose() }
}
return state

The only difference is that it uses remember to allow access to values inside the @composable function.

EffectWithKey was added to handle effect scope inside setContent. The key issued as an argument for LaunchedEffect which displays Snackbars. It is unique for every effect so a new Compose Side Effect is launched for every new Elmslie Effect.

rcmkt commented

Snackbar is not an effect in Compose, you should forget it :) It's a part of the state

rcmkt commented

And I can call 'handleEffect' inside DisposableEffect

Maybe i don't understand something. I agree that it's possble to put snackars to state, but it is true for MVI or ELM as well. But i don't think it would be convenient. Separating effects allows sending multiple Snackbars at once. The same thing could be implemented by keeping a ist of effects in state and sending an Event to remove it from state every time one of them is dismissed. That would be more complicated than keeping effects separately. Do you know of any other way to implement this?

I guess we were talking about different things, i didn't understand that your case with handleEffect is a separate quesion. My point was that you wouldn't be able to call handleEffect if it was @composable.
But then how would your snippet help? Now, handleEffect works out of the box, because it's it implemented anyway in ElmScreen and EffectWithKey is used only for effects that would require @composable handler function which can't be called from DisposableEffect

I'm closing this issue, because there's no activity on this issue for a couple of months. Feel free to reopen this, if there will be any updates on this subject.