Moved to my new blog: jasonformat.com/wtf-is-jsx
It's actually really straightforward. Take 1 minute and read this.
You declare this per-file or per-function to tell your transpiler (eg: Babel) the name of a function that should be called (at runtime) for each node.
In the example below, we are saying "inject calls to an h()
function for each node":
/** @jsx h */
Before:
/** @jsx h */
let foo = <div id="foo">Hello!</div>;
After:
var foo = h('div', {id:"foo"}, 'Hello!');
That's all there is going on here. It's just a sugar for a syntax that's already pretty decent.
First, we'll need to define that h()
function our transpiled code is calling:
function h(nodeName, attributes, ...args) {
let children = args.length ? [].concat(...args) : null;
return { nodeName, attributes, children };
}
Ok, that was easy. The ...args
bit is for multiple child nodes.
Now we have these nested JSON objects our h()
function spits out, so we end up with a "tree" like this:
{
nodeName: "div",
attributes: {
"id": "foo"
},
children: ["Hello!"]
}
So we just need a function that accepts that format and spits out actual DOM nodes:
function render(vnode) {
if (typeof vnode==='string') return document.createTextNode(vnode);
let n = document.createElement(vnode.nodeName);
Object.keys(vnode.attributes || {}).forEach( k => n.setAttribute(k, vnode.attributes[k]) );
(vnode.children || []).forEach( c => n.appendChild(render(c)) );
return n;
}
Sweet.
const ITEMS = 'hello there people'.split(' ');
// a "partial" that does a filtered loop - no template BS, just functional programming:
function foo(items) {
// imagine templates that adhere to your JS styleguide...
return items.map( p => <li> {p} </li> ); // <-- can be multiline
}
// a simple JSX "view" with a call out ("partial") to generate a list from an Array:
let vdom = (
<div id="foo">
<p>Look, a simple JSX DOM renderer!</p>
<ul>{ foo(ITEMS) }</ul>
</div>
);
// render() converts our "virtual DOM" (see below) to a real DOM tree:
let dom = render(vdom);
// append the new nodes somewhere:
document.body.appendChild(dom);
// Remember that "virtual DOM"? It's just JSON - each "VNode" is an object with 3 properties.
let json = JSON.stringify(vdom, null, ' ');
// The whole process (JSX -> VDOM -> DOM) in one step:
document.body.appendChild(
render( <pre>{ json }</pre> )
);