DEV Community 👩‍💻👨‍💻

artydev
artydev

Posted on

Morphdom and MVU, don't overlook this !

If you haven't read the first article on MVU, I invite you to do so.

Let's continue our adventures with MVU.
This time we will code a very simple counter web component.

Without any ceremony here is the definition of our component.
As you can see, there is very little stuff in it.

class MyCounter extends HTMLElement {
    constructor() {
        super()
        this.state = {
            count: Number(this.getAttribute("init")) || 0
        }
        this.append(myCounter(this))
    }
    update() {
        render(this, myCounter(this))
    }
}

customElements.define('my-counter', MyCounter);
Enter fullscreen mode Exit fullscreen mode

In fact the most 'heavy' part is the implementation of the 'myCounter' MVU component.

Let's see how it is coded :

First let's create some helpers using the m function from MVU

const div = m("div") // div maker
let button = m("button") // button maker 

let styleCounter = `
  display:flex
`
let styleButton = `
  color:red
`
let styleValue = `
  font-size: 24px;
  margin-left: 10px;
  margin-right: 10px;
  user-select: none;
`
const styleButtons = {style:styleButton}
Enter fullscreen mode Exit fullscreen mode

And now the actual implementation of our 'counter' using dom, udom functions from MVU and our previous helpers

function myCounter(elt) {

    let state = elt.state;

    let inc = (incr) => () => {state.count += incr; elt.update()};

    let counter = dom();
    button("inc", styleButtons).onclick = inc(1);
    div(`<div>Counter : ${state.count}</div>`, {style:styleValue});
    button("dec", styleButtons).onclick = inc(-1);
    udom();

    counter.style = styleCounter;

    return counter;
}
Enter fullscreen mode Exit fullscreen mode

You are certainly wondering where is morphdom in this piece of code ?

In fact render is an alias for morphdom.

It's called whenever we click on the buttons through the update method.

Let us now use our newly web component :

<my-counter init="27"></my-counter>
<my-counter init="13"></my-counter>
<my-counter init="9"></my-counter>
Enter fullscreen mode Exit fullscreen mode

I hope you see how esay it is to create a simple web component using MVU functions, no hooks, no bindings, no need to modify directly the elements...

Of course, it is not complete, but for a first try it does the job.

Here is the full code :

import "https://cdn.jsdelivr.net/gh/artydev/mvu@DMLMorph/dist/mvu.es.js";

const div = m("div")
let button = m("button")

let styleCounter = `
  display:flex
`

let styleButton = `
  color:red
`

let styleValue = `
  font-size: 24px;
  margin-left: 10px;
  margin-right: 10px;
  user-select: none;
`

const styleButtons = {style:styleButton}

function myCounter(elt) {
    let state = elt.state;
  let inc = (incr) => () => {state.count += incr; elt.update()};
    let counter = dom();
      button("inc", styleButtons).onclick = inc(1);
      div(`<div>Counter (${state.item}) : ${state.count}</div>`, {style:styleValue});
          button("dec", styleButtons).onclick = inc(-1);
    udom();
  counter.style = styleCounter;
    return counter;
}

class MyCounter extends HTMLElement {
    constructor() {
        super()
        this.state = {
      item: this.getAttribute("item"),
            count: Number(this.getAttribute("init")) || 0
        }
  }
  connectedCallback () {
        this.append(myCounter(this))
    }

    update() {
        render(this, myCounter(this))
    }
}

customElements.define('my-counter', MyCounter);
Enter fullscreen mode Exit fullscreen mode

You can test it here : WebComponentMorphDom

Top comments (0)

🤯

"I made 10x faster JSON.stringify() functions, even type safe"

☝️ Must read for JS devs