Lately React, Vue and Svelte have converged on similar concepts for building reactive interfaces. Their syntax differs, but every reactive frontend still uses some form of state, computed values, mutations and effects.

Nevertheless, there is a lot of knowledge involved in getting something basic working in any of these frameworks. In this blog post I will explore what the most stripped down version of such a framework could look like, while still keeping the ergonomics of a reactive framework.

Let's get right into it.

Imagining the framework

To make this concrete, I built a small framework called effectlayer. I will explain its building blocks in this blog post.

Building blocks

The framework is built around a single JavaScript class, which the framework enhances with reactive behavior. That reactivity is powered by Signals, a common primitive used in frameworks such as Vue, Svelte, and SolidJS.

State

All class properties are treated as state. The framework turns them into Signals, so no state annotations are needed here:

class MoodSwing {
  energy = 5;
  coffee = 0;
}

Computed Values

Computed values use standard JavaScript getters. The framework treats them as derived Signals that update automatically when their dependencies change:

  get mood() {
    if (this.energy > 8) return "đŸ€Ș";
    if (this.energy > 4) return "😀";
    if (this.energy > 0) return "😑";
    return "😮";
  }

Mutations

Methods are a natural fit for mutations:

  drinkCoffee() {
    this.coffee++;
    this.energy = Math.min(10, this.energy + 3);
  }

  work() {
    this.energy = Math.max(0, this.energy - 2);
  }

Effects

The last concept we need is effects. Effects are a fancy way of saying "a thing that executes when dependent Signals change".

I chose methods starting with $ for annotating them:

  $monitor() {
    if (this.coffee > 10) console.warn("You may want to slow down.");
  }

The framework sees that $monitor() uses coffee. After coffee changes, it calls the method again.

HTML

Rendering HTML is also an effect that just returns JSX.

  $ui() {
    return (
      <main>
        <h1>{this.mood}</h1>
        <button onClick={() => this.drinkCoffee()}>☕ Coffee</button>
        <button onClick={() => this.work()}>đŸ’» Work</button>
      </main>
    );
  }

All that is left is to make the class reactive by wrapping it in an effectlayer call:

const moodSwing = effectlayer(MoodSwing);
moodSwing.$monitor();
document.body.appendChild(moodSwing.$ui());

Calling an effect once activates it. This means $monitor() will now run whenever coffee changes.

The $ui() call returns an HTML element and keeps it up to date.

All the concepts we need

So basically the framework only needs four concepts:

  • properties for state
  • getters for computed values
  • methods for mutations
  • methods starting with $ for effects

If you want to try out this experimental framework use:

npm create effectlayer

Or check it out on npm.

Deep Dive?

Let me know if you want to see a deep dive into how I built this framework: falk.zwimpfer@liip.ch