Making Components with Template Engines
Tags: javascript, html, react, frontend
Published: 2019-10-14 02:13:17

---
title: Making Components with Template Engines
published: true
description: How to Make a React-like Component with HTML
tags: Javascript, HTML, React, Front-end
---

There's no doubt that components are here to stay.  Templating, in the traditional sense, is kind of fading.  At best you wrap all your React components in a layout partial and call it a day.  Every chunk of reusable UI is becoming Virtual DOM or is at least migrating that way.

But what if you're stuck with using tried and true template engines like JSP, Thyemleaf, Pug, or Razor?  Are you doomed to Partial-Hell forever?

Not really.  You can still build React-like components with Vanilla JS and HTML includes with the ultralight framework <a href="https://github.com/tamb/domponent" target="_blank">Domponent</a>.

For the sake of brevity, let's define a component as having the following and let's base our Vanilla JS on React:

1. Declarative Markup
2. Event Handling
3. Cached DOM references
4. Internal State

Just for good measure here are the component structures:
And here's our directory structure:

React
```
components/
  |
   Counter/
      |
      |Counter.js
      |Counter.scss
```
Domponent
```
components/
  |
    Counter/
      |
      |Counter.html
      |Counter.js
      |Counter.scss
```

## Declarative Markup
Let's make a counter in React.  Here's our JSX.

```js
<div>
  <div>{this.state.count}</div>
  <button type="button" onClick={this.decrement}>
   -1
  </button>
  <button type="button" onClick={this.increment}>
   +1
  </button>
</div>

```

Super simple.  Super easy to understand.  One `button` increments, one decrements, and a `div` shows the count.

How might our HTML look:
```html
<div data-component="Counter">
  <p data-bind="state:Counter.count">0</p>
  <button data-action="click->Counter.decrement">
    -1
  </button>
  <button data-action="click->Counter.increment">
    +1
  </button>
</div>

```

Let's pick this apart by the `data-` attributes:

`data-component` defines which Component your Markup is tied to.  It acts as a root element for your component.

`data-bind` is a bit more complex.  The left side of the colon `:` dictates that we are binding state.  Much like `this.state.count` in React.  The right side of the colon represents the Component we are retrieving state from.  Then you break down the right side by its period `.` The left side is still the Component, while the right side is the key inside of the component state we are displaying.  So here's a quick overview:
```html
state:Component.stateKey
```
## Event Handling
`data-action` is an attribute that accepts any `Event` type `addEventListener` accepts and can event accept <a href="https://github.com/tamb/domponent/blob/master/README.md#data-action" target="_blank">options</a>.

The basic html you need is
```html
data-action="eventtype->component.method"
```

Now you can tie your button in your javascript like so:

```js
import { Component } from "domponent";

export default class Counter extends Component {
  constructor(el) {
    super(el);
  }

  increment() {
    this.setState({ count: this.state.count + 1 });
  }

  decrement() {
    this.setState({ count: this.state.count - 1 });
  }
}

```

## Cached DOM references
Each class in domponent has a `$root` which is the DOM node that contains `data-component`.  You can reference it inside your component class with `this.$root`

`data-ref` works as a simple tag to tell Domponent to cache this node in memory.  
```html
data-ref="component.refName"
```

You can then access the element with `this.refName` where `this` is the component instance and  `refName is the field name you give the cached element.

`data-ref-array` works similarly but it assigns the value as an array in your component and can hold multiple elements.


## Internal State
Each Component has the following lifecycle methods:
* stateWillUpdate
* propsWillUpdate
* propsDidUpdate
* stateDidUpdate

These are exposed and will be called in order every time you fire `this.setState`.  `setState` updates the internal state of the component and updates any relevant `data-bind`elements and any child components that rely on its state.

So that's it.  You can check out some examples of the markup using some popular template engines <a href="https://github.com/tamb/domponent/blob/master/README.md#syntax-examples" target="_blank">here</a>