public static IReactionDisposable Reaction(Action expression, Action effect, IReactionOptions <object> options = null) { return(Reaction((reaction) => { expression(); return Null; }, (value, reaction) => { effect(); }, new ReactionOptions <object>() { Comparer = new LambdaComparer <object>((a, b) => false) })); }
public static IReactionDisposable Reaction <T>(Func <IReactionPublic, T> expression, Action <T, IReactionPublic> effect, IReactionOptions <T> options = null) { var name = options?.Name ?? $"Reaction@{States.NextId}"; var runSync = options == null || options.Scheduler != null && options.Delay == 0; var scheduler = CreateScheduler(options); var firstTime = true; var isScheduled = false; T value = default(T); var comparer = options?.Comparer ?? EqualityComparer <T> .Default; var _reaction = new Reaction( name, (reaction) => { if (firstTime || runSync) { reactionRunner(reaction); } else if (!isScheduled) { isScheduled = true; scheduler(() => reactionRunner(reaction)); } }, options?.OnError ); void reactionRunner(Reaction reaction) { isScheduled = false; // Q: move into reaction runner? if (reaction.IsDisposed) { return; } var changed = false; reaction.Track(() => { var nextValue = expression(reaction); changed = firstTime || !comparer.Equals(value, nextValue) || Null == (object)nextValue; value = nextValue; return(value); }); var firImmediately = options?.FireImmediately; if (firstTime && firImmediately.HasValue && firImmediately.Value) { effect(value, reaction); } if (!firstTime && changed) { effect(value, reaction); } if (firstTime) { firstTime = false; } } _reaction.Schedule(); return(_reaction.GetDisposable()); }