[][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 Transmitters, Receivers 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;
  type DomNode = HtmlElement;

  fn view(&self, tx: Transmitter<In>, rx:Receiver<Out>) -> Gizmo<HtmlElement> {
    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 Component::view 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::ViewMsgs 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 Gizmo using the Gizmo::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 Gizmo.

SimpleComponent

A simple component made from a BuilderFn.