Can/should postSideEffect be called from outside a...
# orbit-mvi
d
Can/should postSideEffect be called from outside an
intent { }
block (like from a Compose button?
g
Can you elaborate?
postSideEffect
and
reduce
can only be called inside
ìntent
. You can have a public fun from the ViewModel that does that
d
Yeah, I guess even side effects should pass through the viewModel/containerHost... I was thinking of calling
containterHost.container.intent { postSideEffect(...) }
straight from the button callback. But you're right, I don't know why I thought I saw it exist on the ContainerHost...
g
containerHost should be private to the ViewModel
and you should hoist everything in the compose side
d
should hoist everything
I made an interface of my ContainerHost's action functions that I pass down through the composables... or do you think it's better to have a bunch of lambdas in the function params?
g
Copy code
@Composable
fun OverviewScreen(
    ...
    viewModel: OverviewViewModel = hiltViewModel(),
) {
    ...

    with(viewModel.state.collectAsStateWithLifecycle().value) {
                MyComposalbe(
                    ...
                    onLoadMore = { viewModel.loadMore() },
                    onDelete = { viewModel.deleteWorkOrder(it) },
                )
            }
    }
    LaunchedEffect(Unit) {
        viewModel.sideEffect.collect {
            ...
        }
    }
}
ViewModel:
Copy code
fun deleteWorkOrder(id: Long) {
    containerHost.intent {
        ...
                    reduce { state.copy(...) }
                    postSideEffect( ... )
                 
                }
            }     
    }
}
an example 😊
BaseViewModel:
Copy code
protected val containerHost = containerHostVisibilityWrapper<STATE, SIDE_EFFECT>(initialState, savedStateHandle) { initContainerHost() }
val state: StateFlow<STATE> = containerHost.container.stateFlow
val sideEffect: Flow<SIDE_EFFECT> = containerHost.container.sideEffectFlow
• containerHost, private to ViewModel • state, sideEffect, public to composable
makes sense to you?
d
Yeah, you're right about hiding the the container, but it seems a bit overkill to have to hoist the actions using lambdas all the way down the hierarchy... even for testing, it's not too hard to pass a Noop fake implementation of that actions interface...
g
true
d
That way you avoid the onLoadMore, onDelete params, and just have:
Copy code
interface Actions {
  fun onLoadMore(...)
  fun onDelete (...)
}

class ContainerHostImpl : ContainerHost..., Actions {
  override fun onLoadMore(...) = intent {...}
...
}
g
Copy code
/**
 * Just to keep it private without public access.
 */
fun <STATE : Parcelable, SIDE_EFFECT : Any> ViewModel.containerHostVisibilityWrapper(
    initialState: STATE,
    savedStateHandle: SavedStateHandle,
    onCreate: ((state: STATE) -> Unit)? = null
) =
    object : ContainerHost<STATE, SIDE_EFFECT> {
        override val container =
            this@containerHostVisibilityWrapper.container<STATE, SIDE_EFFECT>(initialState, savedStateHandle = savedStateHandle, onCreate = onCreate)
    }