Effect
Behavior that is performed as a reaction to an Action.
Returns once with a single Action that is dispatched to the Store. For observing Flows or other many-value sources, see FlowEffect.
An effect is a coroutine that runs in the CoroutineContext of the Store. It returns an Action, which is dispatched to the Store. This is how the result of an effect is communicated back to the store. The completion of an effect is regarded as an event in the outside world like all other events. This way, its result follow the same pathway as other Actions, with the benefit of logging and usage of the thread-safe state update pattern.
An effect has data points to allow reattributing it to other parts of the system:
triggerAction: The Action this effect is being performed as a reaction to.
effectId: The unique id of this effect. Also used for cancellation with Reaction.Cancel
ownerId: An optional owner of this effect. See the documentation of Store for an explanation of the owner concept.
Effects are launched directly after the Reducer, before the Action is handled. They run concurrently to the reducer chain. A queued action will immediately be handled while the effect is running.
Creation is commonly done with the effect() { } builder:
effect(
effectId = effectIdSource.generateId(),
triggerAction = action,
ownerId = action.ownerId,
) {
SomeAction.DataLoaded(repository.loadData())
}Creation is done in Reducer.reduce by passing it to the Reduction as a reaction:
Reduction(
newState,
effect(source.generateId(), action) { /* ... */}
)Uncaught exceptions occurring in an effect reach the Store. See its documentation for the implications. In general, exceptions should be handled in the effect:
effect(/* ... */) {
try {
SomeAction.DataLoaded(repository.loadData())
} catch (e: IOException) {
SomeAction.DataLoadFailed(e)
}
}Passing information into effects
Often, when running an effect, some input data is required. It can be passed in when the effect is created:
// in Reducer.reduce
val action = SomeDataAction(dataCategory: String) // action the reducer is handling
val dataId = state.dataId
Reduction(
/* ... */,
effect(/* ... */) {
// Runs later, `dataId` has the value from the point in time where the reducer was run
val data = repository.loadData(dataId, action.dataCategory)
SomeAction.DataLoaded(data)
}
)See also
Properties
The Action that triggered this effect. Can contain parameters for this effect.