[−][src]Module mogwai::component
Elmesque components through model and view message passing.
Sometimes an application can get so entangled that it's hard to follow the
path of messages through Transmitter
s, Receiver
s and fold functions. For
situations like these where complexity is unavoidable, Mogwai provides the
Component trait and the helper struct GizmoComponent
.
Many rust web app libraries use a message passing pattern made famous by the Elm architecture to wrangle complexity. Mogwai is similar, but different
- Like other libraries, messages come out of the DOM into your component's model by way of the Component::update function.
- The model is updated according to the value of the model message.
- Unlike Elm-like libraries, view updates are sent out of the update function by hand! This sounds tedious but it's actually no big deal. You'll soon understand how easy this is in practice.
Mogwai lacks a virtual DOM implementation. One might think that this is a disadvantage but to the contrary this is a strength, as it obviates the entire diffing phase of rendering DOM. This is where Mogwai gets its speed advantage.
Instead of a virtual DOM Mogwai uses one more step in its model update. The
Component::update
method is given a Transmitter<Self::ViewMsg>
with which
to send view update messages. Messages sent on this transmitter will in
turn be sent out to the view to update the DOM. This forms a cycle. Messages
come into the model from the view, update, messages go into the view from the
model. In this way DOM updates are obvious. You know exactly where, when and
why updates are made (both to the model and the view).
Here is a minimal example of a Component
that counts its own clicks.
extern crate mogwai; use mogwai::prelude::*; #[derive(Clone)] enum In { Click } #[derive(Clone)] enum Out { DrawClicks(i32) } struct App { num_clicks: i32 } impl Component for App { type ModelMsg = In; type ViewMsg = Out; fn builder(&self, tx: Transmitter<In>, rx:Receiver<Out>) -> GizmoBuilder { button() .tx_on("click", tx.contra_map(|_| In::Click)) .rx_text("clicks = 0", rx.branch_map(|msg| { match msg { Out::DrawClicks(n) => { format!("clicks = {}", n) } } })) } fn update(&mut self, msg: &In, tx_view: &Transmitter<Out>, _sub: &Subscriber<In>) { match msg { In::Click => { self.num_clicks += 1; tx_view.send(&Out::DrawClicks(self.num_clicks)); } } } } pub fn main() -> Result<(), JsValue> { App{ num_clicks: 0 } .into_component() .run() }
The first step is to define the incoming messages that will update the model.
Next we define the outgoing messages that will update our view. The builder
trait method uses these message types to build the view. It does this by
consuming a Transmitter<Self::ModelMsg>
and a Receiver<Self::ViewMsg>
.
These represent the inputs and the outputs of your component. Roughly,
Self::ModelMsg
comes into the update
function and Self::ViewMsg
s go out
of the update
function.
Communicating to components
If your component is owned by another, the parent component can communicate to
the child through its messages, either by calling GizmoComponent::update
on the child component within its own update
function or by subscribing to
the child component's messages when the child component is created (see
Subscriber
).
Placing components
Components may be used within a GizmoBuilder
using the
GizmoBuilder::with
function.
Modules
subscriber | A very limited transmitter used to map messages. |
Structs
GizmoComponent | A component and all of its pieces. |
Traits
Component | Defines a component with distinct input (model update) and output (view update) messages. |
Type Definitions
BuilderFn | The type of function that uses a txrx pair and returns a GizmoBuilder. |
SimpleComponent | A simple component made from a BuilderFn. |