Experimental React-like library to build DOM
npm install @internet/dom- :warning: Experimental React-like library to build DOM, without setState and patching.
- Own JSX implementation using h pragma.
- render method to render and mount jsx
- cloneElement to clone a virtual node with new props or new children
- Class Component with react-like lifecycle methods.
- Callback refs support.
- You can also render "real" HTML Elements inside virtual dom
- This is useful to add a Component-oriented architecture on top of an already existing html page (like rendered from PHP)
- You can render "real" HTML Element inside virtual dom (using render or component.render)
- It's the one of the reasons why there isn't patching
- It's a great feature to add a Component-oriented architecture on top of an already existing html page (like rendered from PHP)
- It also means that the virtual dom is absolutely not a source of thruth :warning::warning:
- It can be super easy to have leaks and a bad lifecycle behaviour, so don't rely too much on this lib
- There is no event management for now. Use addEventListener / removeEventListener with lifecycle methods to be sure of what you are doing.
- render have different arguments than the preact / React one.
- component.render is used to render portions of jsx inside it, as child of the component
- the initial rendering of the component is made via the component.template method instead
sh
using npm
$ npm install --save @internet/domor using yarn
$ yarn add @internet/dom
`
API
`js
import { h, render, Component, cloneElement, addRef } from '@internet/dom'
`- :pencil: h(): _Creates a VNode (usually used through JSX)_
- :movie_camera: render(): _Renders a virtual node and mount-it into a
parent Element_
- :orange_book: Component Class: _Base Component class with lifecycle and rendering methods_
- :floppy_disk: cloneElement(): _Clones the given virtual node, optionally replacing its props / children_
- :mag: addRef(): _Quick util to add callback refs to jsx_
:pencil:
h([tag|Component], [props={}], ...children)
> Creates a VNode (virtual DOM element).Kind: global function
Returns: object - A vnode object containing its type, props, children and some flags
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| nodeName | string \| function | | A tagname or a component. e.g.
'div', 'a', Component |
| [props] | object | {} | Attributes/props to set on the created element. |
| [...children] | Array.<VNode> | [] | All additional arguments are vnode children |Example
`js
import { h, render } from '@internet/dom'// Create a new vnode using JSX (via Babel or Bublé)
const node =
Hello// The same node can be made using directly the
h function
const node = h('div', { style: 'color: red' }, 'Hello')// render the created node into
render(node, document.body)
`
:movie_camera:
render(VNode, parent)
> Renders a virtual node and mount-it into a parent Element> :warning:
render always dispatch lifecycle events. Even if you don't pass a parent as 2nd argument, all componentDidMount methods and callback refs will be called. Be carreful!> :warning: If you render a virtual node inside an already mounted component,
use its component.render method instead.
Otherwise, the rendered subcomponents and callback refs will not be register as "childs" of the parent component.
This can lead to bad lifecycle dispatching if you destroy the parent for instance.
Kind: global function
Returns: object - Return an object containing:
-
result.nodes : Array of rendered DOM nodes
- result.components : First-level components instances
- result.refs : First-level callback refs | Param | Type | Description |
| --- | --- | --- |
| vnode | object | A (JSX) VNode to render |
| [parent] | HTMLElement \| function | DOM Element to render into. You can also use a callback function: the function will be called with DOM Elements to mount as first argument |
| [parentComponent] | Component | The parent component instance where the vnode will be mounted. You can directly use
parentComponent.render(vnode, parent) |Example
`js
import { h, render } from '@internet/dom'
import App from 'components/App'// Instanciate an App component and append it to document.body
render( , document.body)
// Insert a new div into document.body, before the first child of document.body
render(
Some text, div => {
document.body.insertBefore(div, document.body.firstChild)
})
`
:orange_book:
Component class
#### Example
`js
import { h, Component, render } from '@internet/raf'class App extends Component () {
template () {
return (
My first app
)
} componentDidMount () {
console.log('App is mounted')
console.log('HTMLElement of the App: ', this.base)
}
}
// Mount a new instance of App component into document.body
// Will call componentWillMount, template and componentDidMount lifecycle events
render( , document.body)
`
#### Component API* Component
* [new Component([props])](#new_Component_new)
* _Methods_
* [.template([props])](#Component+template) ⇒ VNode \| HTMLElement
* [.componentWillMount([props])](#Component+componentWillMount)
* [.componentDidMount([props])](#Component+componentDidMount)
* [.componentWillUnmount([props])](#Component+componentWillUnmount)
* [.render(vnode, [parent])](#Component+render) ⇒ object
* .destroy()
* _Properties_
* .props : object
* .base : VNode \| HTMLElement \| array
* .mounted : boolean
#### new Component([props])
Create a new Component
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [props] | object | {} | Component properties / attributes. Can also contains children. |
*
#### component.template([props]) ⇒ VNode \| HTMLElement
>
component.template will be called during the component initial rendering to create the component.base nodeKind: instance method of Component
Returns: VNode \| HTMLElement - VNode (JSX or
h calls) or real HTMLElement that will be rendered as the component.base node. You can also return an array of elements.
Category: Methods | Param | Type | Default | Description |
| --- | --- | --- | --- |
| [props] | object | {} |
component.props automatically passed as argument. |Example
`js
import { h, Component, render } from '@internet/dom'class HelloDiv extends Component {
template () {
// will create a new p tag
return
Hello!
}
}
// Append a new "Hello!" div to document.body
render( , document.body)class MainComponent extends Component {
template () {
// use the existing node as the component base
return document.querySelector('main')
}
}
// Create a new MainComponent, using an already existing dom node
render( )
` *
#### component.componentWillMount([props])
>
component.componentWillMount will be called by render just before a the component template renderingKind: instance method of Component
Category: Methods
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [props] | object | {} |
component.props automatically passed as argument. |
*
#### component.componentDidMount([props])
>
component.componentDidMount will be called by render when all the rendered dom tree is mountedKind: instance method of Component
Category: Methods
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [props] | object | {} |
component.props automatically passed as argument. |
*
#### component.componentWillUnmount([props])
>
component.componentWillUnmount will be called when the component or one of its ancestors is destroyedKind: instance method of Component
Category: Methods
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| [props] | object | {} |
component.props automatically passed as argument. |
*
#### component.render(vnode, [parent]) ⇒ object
> Render a vnode or array of vnodes and register the rendered content as "child" of this component.
> Use this method when you want to add content to the component after the initial rendering.
> This ensures new items will be correctly unmount when the component is destroyed.
Kind: instance method of Component
Returns: object - Return an object containing rendered
nodes, components and refs
Category: Methods | Param | Type | Description |
| --- | --- | --- |
| vnode | object | A (JSX) VNode to render |
| [parent] | HTMLElement \| function | DOM Element to render into. You can also use a callback function: the function will be called with DOM Elements to mount as first argument |
Example
`js
import { h, Component, render } from '@internet/dom'class Item extends Component {
template () {
return
Item
}
}class List extends Component {
template () {
return (
{ this.ul = el }}>
)
} addItem () {
// Render a new Item instance and add it to the list
// All created Items will be properly destroyed when the List instance is removed
this.render( , this.ul)
}
componentDidMount () {
this.addItem = this.addItem.bind(this)
this.button.addEventListener('click', this.addItem)
}
componentWillUnmount () {
this.button.removeEventListener('click', this.addItem)
}
}
render(
, document.body)
` *
#### component.destroy()
Destroy the component and its children components.
- This also removes component props and de-reference the component from its parent.
- Callback refs inside the component tree will be called with
null as first argument
- Set component.mounted to falseKind: instance method of Component
Category: Methods
Example
`js
import { h, Component, render } from '@internet/dom'class SelfDestructButton extends Component {
template() {
return
}
componentDidMount() {
this.destroy = this.destroy.bind(this)
this.base.addEventListener('click', this.destroy)
}
componentWillUnmount() {
this.base.removeEventListener('click', this.destroy)
}
}
render( , document.body)
` *
#### component.props : object
> Contains all component properties and children.
> Do not modify it directly, but recreate a new component using
cloneElement insteadKind: instance property of Component
Category: Properties
*
#### component.base : VNode \| HTMLElement \| array
> HTMLElement used as "base" for the component instance. Can also be an array of elements if
template return an array.Kind: instance property of Component
Category: Properties
*
#### component.mounted : boolean
Set to true when component is mounted
Kind: instance property of Component
Category: Properties
*
:floppy_disk:
cloneElement(VNode, [newProps={}], [newChildren])
> Clones the given virtual node, optionally updating its props and replacing its childrenKind: global function
Returns: object - A new vnode object containing updated props / children
| Param | Type | Default | Description |
| --- | --- | --- | --- |
| vnode | object.VNode | | A virtual node object to clone |
| [props] | object | {} | Attributes/props to set on the created element. |
| [...children] | Array.<VNode> | [] | All additional arguments are vnode children |
Example
`js
import { h, render, cloneElement } from '@internet/dom'const useRed = (vnode) => cloneElement(vnode, { style: 'color:red;' })
const normalText =
Some text
const redText = useRed(normalText)render(redText, document.body)
`
:mag:
addRef(obj, refName)
> Create a callback ref functionKind: global function
Returns: function - A callback ref function
| Param | Type | Description |
| --- | --- | --- |
| obj | object \| function | Object or Component instance to add the reference to |
| refName | string | Name of the reference. Will be accessible from
obj[refName] |Example
`js
import { h, render, addRef, Component } from '@internet/dom'class App extends Component () {
template () {
return (
) componentDidMount () {
console.log('Button is mounted:', this.button)
}
}
}
render( , document.body)
``