Skip to content
Fred Daoud edited this page Nov 28, 2017 · 3 revisions

Using JSX with domvm

While it is not possible to get 100% of domvm's features with JSX, you can get a lot done with defineElementSpread as your JSX pragma:

/* @jsx domvm.defineElementSpread */

const view = name => (
  <div>Hello, {name}</div>
);

const logEl = document.getElementById("log");
const log = str => logEl.innerHTML += str + " ";

const myFn = () => log("clicked");
const myFn2 = (arg1, arg2) => log("clicked " + arg1 + "," + arg2);

const NavBarView = navbar => (<span>{navbar}</span>);
const PanelView = (panelview, key) => (<span _key={key}>{panelview}</span>);

const view2 = () => (
<div>
  <p>Hello</p>                                                    {/* plain tags */}
  <textarea id="foo" class="bar baz" rows="10">Hello</textarea>   {/* attr, id & class shorthands */}
  <div class="kitty">Hello</div>                                  {/* "div" can be omitted from tags */}
  <input type="checkbox" checked={true}/>                         {/* boolean attrs */}
  <input type="checkbox" checked={true}/>                         {/* set property instead of attr */}
  <button onclick={myFn}>Hello</button>                           {/* event handlers */}
  <button onclick={[myFn2, "arg1", "arg2"]}>Hello</button>        {/* parameterized */}
  <ul onclick={{".item": myFn}}>                                  {/* delegated */}
    <li class="item" style="cursor: pointer">Item 1</li>
    <li class="item" style="cursor: pointer">Item 2</li>
  </ul>
  <ul onclick={{".item": [myFn2, "arg1", "arg2"]}}>               {/* delegated and parameterized */}
    <li class="item" style="cursor: pointer">Item 3</li>
    <li class="item" style="cursor: pointer">Item 4</li>
  </ul>
  <p style="font-size: 10pt;">Hello</p>                           {/* style can be a string */}
  <p style={{fontSize: "10pt"}}>Hello</p>                         {/* or an object (camelCase only) */}
  <div style={{width: 35}}>Hello</div>                            {/* "px" will be added when needed */}
  <h1>                                                            {/* attrs object is optional */}
    <em>Important!</em>
    foo 123                                                       {/* plain values */}
    <br/>                                                         {/* void tags without content */}
    {""} {[]} {null} {undefined} {false}                          {/* these will be auto-removed */}
    {NaN} {true} {{}} {Infinity}                                  {/* these will be coerced to strings */}
    {/* nested arrays will get flattened */}
    {/* short & attr class get merged: .foo.bar */}
    {[
      <div class="foo bar">
        {[
          "baz",
          <hr/>
        ]}
      </div>
    ]}
  </h1>
  <div id="ui">
    {NavBarView("navbar")}                                        {/* sub-view w/data */}
    {PanelView("panelview", "panelA")}                            {/* sub-view w/data */}
  </div>
  <p _key="myParag">Some text</p>                                 {/* keyed nodes */}
  <p _data={{foo: 123}}>Some text</p>                             {/* per-node data (faster than attr) */}
  <p _ref="myParag">Some text</p>                                 {/* named refs (vm.refs.myParag) */}
  <p _ref="pets.james">Some text</p>                              {/* namespaced (vm.refs.pets.james) */}
  <div _flags={domvm.FIXED_BODY}>Some text</div>                  {/* optimization flags */}
</div>);

const AppView = () => (vm, data) => view2(data);
const vm = domvm.createView(AppView);
const element = document.getElementById("app");
vm.mount(element);

Try it out: https://codepen.io/foxdonut/pen/KyBzmy?editors=0010

Furthermore, you can also define components with a bit of customization on the JSX pragma:

/** @jsx el */

const el = (...args) => {
  const type = typeof args[0];
  if (type === 'function') {
    const view = args[0];
    const data = args[1] || {};
    data.children = args[2];
    return domvm.defineView(view, data, data.key);
  }
  return domvm.defineElementSpread(...args);
}

const Component = (vm) => {
  console.log(vm);
  return (vm) => {
    console.log('draw');
    return (
      <div>{vm.data.step}{vm.data.children}</div>
    )
  }
}

function View(vm) {
  let step = 0;
  let v;
  setInterval(()=> {
    step = step +1;
    vm.redraw();
  }, 1000)
  return function() {
    return (
      <div>
        <Component
          name='foo'
          step={step}
        >
          <div><h1>I am a child</h1></div>
        </Component>
      </div>
    );
  };
}

const vm = domvm.createView(View);
vm.mount(document.getElementById('root'));

Try it out: https://jsfiddle.net/kqurpfqk/

JSX offers the lowest common denominator, but there are numerous other factories in domvm that provide many things JSX cannot do. Another issue is that svg has its own factory in domvm, whereas JSX does not and would need help to disambiguate that during transpilation.

Still, it's nice to know that you can get a great deal of domvm's features with JSX and can work nicely say in an application where you don't need svg.

Clone this wiki locally