Summary
Introduce a Roslyn analyzer that generates a compile time error when a class implementing IEffect injects IStatePulse.
Problem
IStatePulse is designed to provide near zero boilerplate state change observation.
Its purpose is to simplify UI layer bindings where components need to react automatically to state updates.
IStatePulse is not intended to be used as a universal state access mechanism and must not be injected inside IEffect handlers.
Effects are ephemeral by design. When an effect handler executes, it already runs in response to a dispatch event and can access the latest state at runtime.
Creating a state pulse binding inside an effect introduces an unnecessary reactive dependency that contradicts the intended lifecycle of effects.
Architectural Intent
IStatePulse:
- designed for UI level state subscriptions
- built for long lived reactive bindings
- internally built on top of
IStateAccessor<TState>
IEffect:
- designed to be short lived and execution scoped
- triggered by dispatch events
- should read state on demand
Because of this mismatch, using IStatePulse inside an effect introduces architectural misuse.
Correct Alternative
If an effect needs to read state, it must use IStateAccessor<TState>:
This provides direct access to the latest state without establishing a reactive subscription.
Example:
public class MyEffect : IEffect<MyAction>
{
private readonly IStateAccessor<MyState> _state;
public MyEffect(IStateAccessor<MyState> state)
{
_state = state;
}
public Task HandleAsync(MyAction action, IDisaptcher disaptcher)
{
var current = _state.Value;
return Task.CompletedTask;
}
}
Example That Should Trigger the Analyzer
public class MyEffect : IEffect<MyAction>
{
private readonly IStatePulse _pulse;
public MyEffect(IStatePulse pulse)
{
_pulse = pulse;
}
}
Summary
Introduce a Roslyn analyzer that generates a compile time error when a class implementing
IEffectinjectsIStatePulse.Problem
IStatePulseis designed to provide near zero boilerplate state change observation.Its purpose is to simplify UI layer bindings where components need to react automatically to state updates.
IStatePulseis not intended to be used as a universal state access mechanism and must not be injected insideIEffecthandlers.Effects are ephemeral by design. When an effect handler executes, it already runs in response to a dispatch event and can access the latest state at runtime.
Creating a state pulse binding inside an effect introduces an unnecessary reactive dependency that contradicts the intended lifecycle of effects.
Architectural Intent
IStatePulse:IStateAccessor<TState>IEffect:Because of this mismatch, using
IStatePulseinside an effect introduces architectural misuse.Correct Alternative
If an effect needs to read state, it must use
IStateAccessor<TState>:This provides direct access to the latest state without establishing a reactive subscription.
Example:
Example That Should Trigger the Analyzer