Counter Example with jQuery

To give you a more concrete idea of Meiosis, let's look at a quick example. We'll create a simple counter with buttons to increase and decrease the value.

You can run this example online here. You will also find it in the meiosis-examples repository. The example uses jQuery, but remember that Meiosis also works with React, Inferno, Mithril, and Snabbdom. In fact, we'll look at the same example with React in the next section.

Creating a Model and a View

We'll start with a model for the counter:

var initialModel = { counter: 0 };

Next, let's write a view function:

var view = function(model) {
  return "<div><span>Counter: " + model.counter + "</span></div>" +
    "<div><button id='inc'>+</button> <button id='decr'>-</button></div>";
};

The function accepts the model as a parameter and returns the view. The view displays the counter and buttons to increase and decrease the value.


Now, don't run away screaming HTML with string concatenation! OH NOES! You can use whatever you like to create views. Virtual DOM libraries such React, Inferno, Snabbdom, and Mithril work especially well with Meiosis. We'll switch to React in the next section. The point is, you don't need to use any particular library. If creating the HTML from simple string concatenation suits your needs, that is fine with Meiosis.


Specifying a Renderer

The way you tell Meiosis how you want to create your views is by specifying a renderer. Meiosis currently provides renderers for:

Implementing a renderer for other libraries is easy. Refer to the Renderers section for more details.

Let's specify the Vanilla JS renderer for our counter example:

var renderer = meiosisVanillaJs.renderer();

Creating a Component

Next, we'll create a component:

var Main = meiosis.createComponent({
  view: view
});

The createComponent function accepts several properties, all of which are optional. Here, we've indicated the view function.

Running Meiosis

The Main component that we've created is also the root, or top-level, component of our application. We need to pass the renderer and the root component to meiosis.run to start Meiosis:

meiosis.run({
  renderer: renderer.intoId(document, "app"),
  initialModel: initialModel,
  rootComponent: Main
});

We've told the renderer to render into the element with the app id of the document. We just need a container with that id in our HTML page:

<div id="app"></div>

Our view will render into that div.

Now, we will see the result of calling the view function with the initialModel.

Sending Proposals

The view renders, but the buttons don't do anything yet. For them to work, they need to send proposals. Meiosis provides a propose function to do precisely that.

Let's use jQuery to attach event handlers to the buttons. Again, note that we'll also look at how we can do this with React.

When creating a component, we can indicate a ready function that will be called once after the initial view has finished rendering. This is where we attach our event handlers:

var ready = function(propose) {
  var $root = $(document.getElementById("app"));

  $root.on("click", "button#inc", function(_evt) {
    propose({ add: 1 });
  });
  $root.on("click", "button#decr", function(_evt) {
    propose({ add: -1 });
  });
};

Meiosis passes the propose function to the ready function. We use it to send proposals. In this case, the proposal is to add an amount to the counter. We pass the ready function to createComponent, which is now:

var Main = Meiosis.createComponent({
  view: view,
  ready: ready
});

Let's finish the example by receiving the proposals.

Receiving Proposals

Finally, we need a function to receive proposals and decide how to change the model:

var receive = function(model, proposal) {
  return { counter: model.counter + proposal.add };
};

The function accepts the proposal and adds the value to the counter. Note that the receive function decides what to do with a proposal. It can also refuse a proposal.

We pass the receive function to createComponent:

var Main = Meiosis.createComponent({
  view: view,
  ready: ready,
  receive: receive
});

Our example is complete!

Try it out

To recap, here is the full code for the example:

var initialModel = { counter: 0 };

var view = function(model) {
  return "<div><span>Counter: " + model.counter + "</span></div>" +
    "<div><button id='inc'>+</button> <button id='decr'>-</button></div>";
};

var receive = function(model, proposal) {
  return { counter: model.counter + proposal.add };
};

var ready = function(propose) {
  var $root = $(document.getElementById("app"));

  $root.on("click", "button#inc", function(_evt) {
    propose({ add: 1 });
  });
  $root.on("click", "button#decr", function(_evt) {
    propose({ add: -1 });
  });
};

var Main = meiosis.createComponent({
  view: view,
  ready: ready,
  receive: receive
});

var renderer = meiosisVanillaJs.renderer();

meiosis.run({
  renderer: renderer.intoId(document, "app"),
  initialModel: initialModel,
  rootComponent: Main
});

You can run this example online here. You will also find it in the meiosis-examples repository.

This is the general idea behind Meiosis. The reactive loop consists of model - view - propose - receive. Meiosis does the wiring so that when you call propose, the receive function gets triggered. The new model is passed to view, which gets re-rendered by the renderer. You will find a more detailed explanation in Meiosis: The Big Picture.

In the next section, we'll look at how to write the counter example with React.

results matching ""

    No results matching ""