pub trait Reducer<StateSlice = ()>:
Send
+ Sync
+ 'static{
type State: Clone + Send + Sync + 'static;
type Action: Send + 'static;
type SideEffect: Send + 'static;
// Required methods
fn init(
&mut self,
ctx: InitContext<Self::SideEffect>,
) -> impl Future<Output = ()> + Send;
fn reduce(
&mut self,
state: &mut Self::State,
action: Self::Action,
) -> CoreResult<StateChange<StateSlice>>;
fn effect(
&mut self,
state: &mut Self::State,
effect: Self::SideEffect,
) -> CoreResult<StateChange<StateSlice>>;
// Provided method
fn infer_slices(
&self,
_before: &Self::State,
_after: &Self::State,
) -> Vec<StateSlice> { ... }
}Expand description
A reducer defines how actions mutate state and how side-effects are applied.
Implementations are expected to be deterministic with respect to their inputs:
given the same state + action/effect, they should produce the same
resulting state and StateChange.
Reducers are intentionally split into three phases:
Reducer::init: async initialization where the reducer can spawn tasks and retain cloned handles tosideeffect_tx.Reducer::reduce: synchronous state transitions driven by user actions.Reducer::effect: synchronous state transitions driven by background work.
Keeping reduce/effect synchronous makes update ordering easy to reason
about (the engine serializes all mutations behind a single mutex), while
still enabling async I/O by performing it in spawned tasks and sending the
result back as a side-effect.
§Threading
Reducers are used by ReducerEngine. Actions are
dispatched serially; you do not need to make your reducer internally
thread-safe beyond the trait bounds.
Required Associated Types§
Sourcetype Action: Send + 'static
type Action: Send + 'static
The action type consumed by Reducer::reduce.
Sourcetype SideEffect: Send + 'static
type SideEffect: Send + 'static
A reducer-defined side-effect type that can be sent to the engine.
Required Methods§
Sourcefn init(
&mut self,
ctx: InitContext<Self::SideEffect>,
) -> impl Future<Output = ()> + Send
fn init( &mut self, ctx: InitContext<Self::SideEffect>, ) -> impl Future<Output = ()> + Send
Called once when the reducer is installed in an engine.
The provided sender can be used by the reducer to enqueue side-effects
(for example, from within Reducer::reduce).
Implementations typically clone ctx.sideeffect_tx and move it into any
background tasks the reducer spawns.
Sourcefn reduce(
&mut self,
state: &mut Self::State,
action: Self::Action,
) -> CoreResult<StateChange<StateSlice>>
fn reduce( &mut self, state: &mut Self::State, action: Self::Action, ) -> CoreResult<StateChange<StateSlice>>
Applies an action to the provided state.
Returning StateChange::Full indicates that a new snapshot should be
emitted to subscribers.
Sourcefn effect(
&mut self,
state: &mut Self::State,
effect: Self::SideEffect,
) -> CoreResult<StateChange<StateSlice>>
fn effect( &mut self, state: &mut Self::State, effect: Self::SideEffect, ) -> CoreResult<StateChange<StateSlice>>
Applies a previously-enqueued side-effect to the provided state.
Side-effects are processed by the engine’s background loop and are intended for work that must be applied out-of-band from normal action dispatch.
Provided Methods§
Sourcefn infer_slices(
&self,
_before: &Self::State,
_after: &Self::State,
) -> Vec<StateSlice>
fn infer_slices( &self, _before: &Self::State, _after: &Self::State, ) -> Vec<StateSlice>
Infers which slices changed between before and after.
This is only used when reducers return StateChange::Infer. Reducers
that do not opt into sliced updates can rely on the default empty
implementation.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.