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 Domponent.
For the sake of brevity, let's define a component as having the following and let's base our Vanilla JS on React:
- Declarative Markup
- Event Handling
- Cached DOM references
- 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.
<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:
<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:
state:Component.stateKey
Event Handling
data-action
is an attribute that accepts any Event
type addEventListener
accepts and can event accept options.
The basic html you need is
data-action="eventtype->component.method"
Now you can tie your button in your javascript like so:
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.
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 here
Top comments (0)