virt
is a tool for creating interactive UIs where you use abstract views for each state in your
application, and virt will find the differences and create a Transaction.
virt was created after reading facebook's React
source code. The difference is virt
creates JSON Transactions that an adapter like virt-dom
uses to render to some native view system, in virt-dom's
case the DOM.
virt-dom
provides adapters to render virt
changes to the DOM over a WebSocket, a WebWorker or from the main javascript thread.
Examples of all three are below.
Real World Example
Full site example here http://bomontfii.com.
github repo for virt views and application logic.
github repo for building and starting application.
Some technical examples
Simple Example Usage
The best way to use virt is to create custom components that inherit from the virt.Component class.
var virt = require("@nathanfaucett/virt"),
virtDOM = require("@nathanfaucett/virt-dom");
function List(props, children, context) {
virt.Component.call(this, props, children, context);
this.state = {
items: [
{id: 0, text: "Item 1"},
{id: 1, text: "Item 2"}
]
};
}
// same as
// List.prototype = Object.create(virt.Component.prototype);
// List.prototype.displayName = "List";
virt.Component.extend(List, "List");
List.prototype.onClick = function(id) {
var _this = this;
this.state.items.forEach(function(value, index, array) {
if (value.id === id) {
array.splice(index, 1);
_this.setState({
items: array
});
return false;
}
});
};
List.prototype.render = function() {
var _this = this;
return (
virt.createView("ul", this.state.items.map(function(item) {
return virt.createView(Item, {
key: item.id,
onClick: function onClick() {
_this.onClick(item.id);
},
text: item.text
});
}))
);
};
function Item(props, children, context) {
virt.Component.call(this, props, children, context);
}
virt.Component.extend(Item, "Item");
Item.prototype.render = function() {
return (
virt.createView("li", {
onClick: this.props.onClick
}, this.props.text)
);
};
virtDOM.render(virt.createView(List), document.getElementById("app"));
Messeger
A messeger
is how all data is sent and received between the views and the renderer. This is used
internally to fix inconsistencies in native DOM elements.
Native DOM Elements
var virt = require("@nathanfaucett/virt");
function HelloWorld(props, children, context) {
virt.Component.call(this, props, children, context);
}
virt.Component.extend(HelloWorld, "example.HelloWorld");
HelloWorld.prototype.componentDidMount = function(id) {
this.emitMessage("example.HelloWorld.mount", {
id: this.getInternalId()
},
// optional callback
function onHandled(error, data) {
if (error) {
// handle error
} else {
// handle any data send from the handler
}
}
);
};
HelloWorld.prototype.render = function() {
return virt.createView("div");
};
var virtDOM = require("@nathanfaucett/virt-dom");
virtDOM.addNativeHandler(
"example.HelloWorld.mount",
function(data, doneCallback) {
var id = data.id,
node = findDOMNode(id);
if (node) {
node.innerHTML = "
Hello, world!
";
// optionally send data back
// doneCallback(undefined, data);
doneCallback();
} else {
doneCallback(new Error("No DOM node found with id " + data.id));
}
}
);
virtDOM.render(virt.createView(HelloWorld), document.getElementById("app"));
Web Worker Example
When using a WebWorker the view processing is handled in the worker while
the main thread only responses to render calls and updates the DOM.
Web Worker Script
var virt = require("@nathanfaucett/virt"),
virtDOM = require("@nathanfaucett/virt-dom/src/worker/server");
virtDOM.render(virt.createView("p", "Hello, world!"));
Main thread
var virtDOM = require("@nathanfaucett/virt-dom/src/worker/client");
virtDOM.createRenderer(
"path-to-worker-script.js",
document.getElementById("app")
);
WebSocket Example
When using WebSockets the main thread only responses to render calls and updates the DOM.
Server
var virt = require("@nathanfaucett/virt"),
virtDOM = require("@nathanfaucett/virt-dom/src/websocket/server"),
socket_io = require("socket.io");
var io = socket_io(),
root = null;
io.on("connection", function(socket) {
virtDOM.render(
virt.createView(virt.createView("p", "Hello, world!")),
socket,
function attachMessage(socket, callback) {
socket.on("client-message", callback);
},
function sendMessage(socket, data) {
socket.emit("server-message", data);
}
);
});
console.log("listening on port 9999");
io.listen(9999);
Client
var io = require("socket.io-client"),
virtDOM = require("@nathanfaucett/virt-dom/src/websocket/client");
var socket = io("localhost:9999");
socket.on("connect", function onConnect() {
virtDOM.createRenderer(
document.getElementById("app"),
socket,
function attachMessage(socket, callback) {
socket.on("server-message", callback);
},
function sendMessage(socket, data) {
socket.emit("client-message", data);
}
);
});
socket.on("error", function(error) {
console.log(error);
});