Side effects allow you to deal with things like tracking, navigation etc.

Side Effect는 트래킹이나 네비게이션과 같은 것을 처리할 수 있다.

postSideEffect 파헤쳐보기

@OrbitDsl
public suspend fun <S : Any, SE : Any> SimpleSyntax<S, SE>.postSideEffect(sideEffect: SE) {
    containerContext.postSideEffect(sideEffect)
}

해당 부분도 intent, reduce DSL과 마찬가지로 ContainerContext 의 프로퍼티를 사용한다. 여기서 사용되는 프로퍼티는 postSideEffect 이다.

ContainterContext - postSideEffect

@OrbitInternal
public class ContainerContext<S : Any, SE : Any>(
    public val settings: RealSettings,
    **public val postSideEffect: suspend (SE) -> Unit,**
    private val getState: () -> S,
    public val reduce: suspend ((S) -> S) -> Unit,
    public val subscribedCounter: SubscribedCounter
) {
    public val state: S
        get() = getState()
}

해당 컴포넌트는 RealContainer 에서 SideEffect 가 변경됨을 보내어 SideEffect가 변하는 것을 알 수 있다.

RealContainer

해당 부분은 코루틴의 Channel을 사용하여 코루틴 간의 데이터 통신을 효율적으로 진행한다. 이렇게 send하게 됨으로 써, collectSideEffect 에서 SideEffect 를 수집할 수 있다.

// RealContainer.kt
**private val sideEffectChannel = Channel<SIDE_EFFECT>(settings.sideEffectBufferSize)**

internal val pluginContext: ContainerContext<STATE, SIDE_EFFECT> = ContainerContext(
        settings = settings,
        **postSideEffect = { sideEffectChannel.send(it) },**
        getState = { internalStateFlow.value },
        reduce = { reducer -> internalStateFlow.update(reducer) },
      subscribedCounter
)

collectSideEffect

// InitViewModel.kt

intent {
  postSideEffect(InitSideEffect.Completed)
}
val viewModel = getComposeViewModel<InitViewModel>()

viewModel.collectSideEffect {
    when (it) {
        is InitSideEffect.Completed -> { ... }
    }
}

ViewModel 에서 intent 블록 내에서 postSideEffect 로 원하는 SideEffect 상태를 보냈을 때, Activity나 Fragment에서 collect 하고있다가 SideEffect 상태에 따라서 분기처리할 수 있다. 이는 Jetpack 네비게이션을 사용하여 원하는 상태가 성공했을 때 해당 SideEffect 를 완료됨을 알려 다음 네비게이션을 진행하는 예시로 많이 사용된다.