Meiosis Wiki

Table of Contents

Reusing Components

Now that we have components, let's look at how we can make components reusable by having multiple instances within the same top-level model.

Multiple Component Instances

Let's say we'd like to reuse the temperature component from our previous example twice on the same page: once for air and once for water temperature. We'd like each component to keep managing its own model, but at the same time we want a single top-level model.

Here is our app which contains two instances of the temperature component:

export const createApp = update => {
  const air = nest(createTemperature, update, "air");
  const water = nest(createTemperature, update, "water");

  return {
    model: () => Object.assign(air.model(), water.model()),
    view: createView({air, water})
  };
};

We've created two instances of the temperature component. However, we did not pass the update function directly to createTemperature; instead, we called a nest function, passing createTemperature, the update function, and the path for each component.

Also notice that our app's initial model has each component's model within the top-level, one for air and one at water.

Finally, we pass our components to the view so that it can render them.

Nesting Updates

The question is, what is nest and how do we write this function so that we nest components with a path?

That is the beauty of the Meiosis pattern: because we are passing functions to update, and because these are functions that get the latest model and return the updated model, it's straightforward to write a nestUpdate function:

const nestUpdate = (update, path) => func =>
  update(model => {
    model[path] = func(model[path]);
    return model;
  });

What nestUpdate does is return a function that wraps update. It takes the incoming func and calls the original update by passing model[path] to func and assigning the result back to model[path].

For example, if the incoming func is the function that increases the value of the temperature:

const func = model => {
  model.value = model.value + amount;
  return model;
};

Then nestUpdate(update, "air") will nest the update at the "air" property of the top-level model:

update(model => {
  model["air"] = func(model["air"]);
  return model;
});

We are ready to nest components.

Nesting Components

Now that we have nestUpdate, we can write the nest function to nest components:

export const nest = (create, update, path) => {
  const component = create(nestUpdate(update, path));
  const result = Object.assign({}, component);
  if (component.model) {
    result.model = () => ({ [path]: component.model() });
  }
  if (component.view) {
    result.view = model => component.view(model[path]);
  }
  return result;
};

We passed the component's create function to nest, and we call it to create the component, passing in the nested update. Now that we've created the component, we can wrap its model and view functions:

We are ready to render the components in the view.

The View

Having created our components containing temperature instances for air and water, we can pass them to the view and render them:

export const createView = components => model => (
  <div>
    <h4>App</h4>
    {components.air.view(model)}
    {components.water.view(model)}
  </div>
);

Notice that when calling view(), we pass model to each instance. The nest function took care of wrapping view() to pass in the nested model.

Principles / Takeaways

Up Next

In the next article, we will look at Computed Properties.

Table of Contents


Meiosis is developed by @foxdonut00 / foxdonut and is released under the MIT license.