eventInterceptor<Context> method
System<State, Event>
eventInterceptor<Context>({
- required Context createContext(),
- ContextEffect<
Context, State, Event> ? updateContext, - required InterceptorWithContext<
Context, Event> interceptor, - void dispose(
- Context context
An interceptor that can intercept event.
This is a low level operator which can be used for supporting high level operators
like system.ignoreEvent
and system.debounceOn
.
API Overview
The key point for this operator is, we are associating a custom Context
with it:
class SomeContext { ... }
...
system
.eventInterceptor<SomeContext>(
createContext: () => SomeContext(), // create context here
updateContext: (context, state, oldState, event, dispatch) {
// update context here if needed.
},
interceptor: (context, dispatch, event) {
// intercept event base on the context,
// call `dispatch(event);` if we pass the event,
// don't call `dispatch(event);` if we ignore the event.
},
dispose: (context) {
// dispose the context if needed.
}
)
...
Usage Example
Below code shown how to implement high level system.ignoreEvent
based on low level system.eventInterceptor
:
class _IgnoreEventContext<State> {
late State state;
}
extension FilterEventOperators<State, Event> on System<State, Event> {
...
/// Ignore event based on current state and candidate event.
System<State, Event> ignoreEvent({
required bool Function(State state, Event event) when
}) {
final test = when;
return eventInterceptor<_IgnoreEventContext<State>>( // <-- call `this.eventInterceptor`
createContext: () => _IgnoreEventContext(),
updateContext: (context, state, oldState, event, dispatch) {
context.state = state; // cache current state in context
},
interceptor: (context, dispatch, event) {
final shouldIgnoreEvent = test(context.state, event);
if (!shouldIgnoreEvent) {
dispatch(event);
}
},
);
}
}
Usage of system.ignoreEvent
:
futureSystem
.ignoreEvent(
when: (state, event) => event is TriggerLoadData && state.loading
)
...
Above code shown if the system is already in loading status,
then upcoming TriggerLoadData
event will be ignored.
We can treat system.ignoreEvent
as a special case of system.eventInterceptor
,
As an analogy, if we say system.ignoreEvent
is a square, then system.eventInterceptor
is a rectangle.
Implementation
System<State, Event> eventInterceptor<Context>({
required Context Function() createContext,
ContextEffect<Context, State, Event>? updateContext,
required InterceptorWithContext<Context, Event> interceptor,
void Function(Context context)? dispose,
}) {
return runWithContext<Context>(
createContext: createContext,
run: (context, run, nextReduce, nextEffect, nextInterceptor) {
bool isDisposed = false;
final Effect<State, Event>? localEffect = updateContext == null ? null : (state, oldState, event, dispatch) {
updateContext(context, state, oldState, event, dispatch);
};
Dispatch<Event> localInterceptor(Dispatch<Event> dispatch) => Dispatch((event) {
if (isDisposed) return;
interceptor(context, dispatch, event);
});
final sourceDisposer = run(
reduce: nextReduce,
effect: combineEffect(localEffect, nextEffect),
interceptor: combineInterceptor(localInterceptor, nextInterceptor),
);
return Disposer(() {
isDisposed = true;
sourceDisposer();
});
},
dispose: dispose,
);
}