How to Access Real DOM Nodes with Mercury/virtual-dom
At work, we are using the Mercury JavaScript UI library, which is a more functional alternative to React (at least this is my understanding of it). It is also highly modular, in that it’s simply composed from several independent libraries (such as virtual-dom).
Like React, Mercury hides the browser DOM behind a virtual model, to improve performance. However, this can cause problems in case you need real access to the DOM. For example, a 3rd party library such as the popular spin.js may require changing the DOM directly, and consequently, the virtual DOM will not suffice.
There is a way to get hold of the real DOM node corresponding to a virtual node thankfully, but it isn’t straightforward.
Virtual Node Hooks
The virtual-dom library supports associating virtual nodes with hooks to be called when a corresponding DOM node is rendered and when it’s removed, respesctively. This is done by supplying an object to the virtual node constructor which has in its prototype a 'hook' method and/or an 'unhook' method. The former gets called when the DOM node has been rendered and the latter after it has been removed. Both methods receive the DOM node as their first argument.
Below is a full example that shows how to register the aforementioned 'hook' and 'unhook' callbacks.
'use strict';
var hg = require('mercury');
var h = require('mercury').h;
function Hook() {}
// Hook to be called when DOM node has been rendered
Hook.prototype.hook = function hook(node) {
node.innerText = 'This is set directly on the real DOM node.';
};
// Hook to be called when DOM node is removed
Hook.prototype.unhook = function unhook(node) {
node.innerText = 'Unhook hook called';
};
function App() {
var state = hg.state({
remove: hg.value(false)
});
setTimeout(function timer() {
state.remove.set(true);
}, 2000);
return state;
}
App.render = function App(state) {
return !state.remove ?
// Create virtual node with hook
h('div', {
hook: new Hook()
}) :
// Node without hook
h('div');
};
hg.app(document.body, App(), App.render);