Callbags + JSX. No virtual DOM, compile-time invalidation, or other magic tricks.
npm i callbag-jsx
import { makeRenderer, List } from 'callbag-jsx';
import { state } from 'callbag-state';
const renderer = makeRenderer();
const todos = state([{title: 'Do this'}, {title: 'Do that'}]);
const next = state('');
const add = () => {
todos.set(todos.get().concat([{title: next.get()}]));
next.set('');
};
renderer.render(<div>
<h1>Todos</h1>
<ol>
<List of={todos} each={todo => <li>{todo.sub('title')}</li>}/>
</ol>
<input type='text' _state={next} placeholder='What should be done?'/>
<button onclick={add}>Add</button>
</div>).on(document.body);
Why?
callbag-jsx
provides convenience of React without taking control away. You can seamlessly control exactly
when and how some part of the DOM tree is updated:
const s = state('');
renderer.render(<>
<input _state={s} type='text' placeholder='Type something ...'/>
<br/>
{ s }
<br/>
{ pipe(s, debounce(200)) }
</>).on(document.body);
callbag-jsx
is integrated with callbag-state
, so there is no need for external
state-management tools such as Redux:
const s = state([0, 0, 0, 0]);
renderer.render(<div>
<List of={s} each={i =>
<div onclick={() => i.set(i.get() + 1)}>clicked {i} times</div>
}/>
<br/>
State: {expr($ => $(s).join(', '))}
</div>).on(document.body);
callbag-jsx
just binds callbags to DOM elements. As a result:
- It is much faster than most popular frameworks.
- Its bundles are much smaller (so faster to ship).
- No bootstrapping besides your own code, so web-apps are quickly interactive.
Benchmarks conducted using JS framework benchmark.
function MyComponent(...) {
const x = <span/>;
// ...
return <div>{x}</div>;
}
Then x
IS the span element that ends up on screen (and not a proxy for it). You just need to know JS(X) to fully understand what happens.
callbag-jsx
is highly interoperable and robust. You can even manually modify the DOM whenever you need to (for example for obtaining maximum possible performance).