Simple JavaScript rendering library with a React-compatible API
I built this mostly to understand how React works under the hood. Currently it supports only a small subset of the React API (3KB minified).
See it live here.
- Function components with hooks (useState, useEffect)
- No dependencies
- Built with TypeScript
npm install --save recat-core
Updates the domRoot
contents using the virtual DOM tree at virtualNode
.
Subsequent render calls will try to make as few writes as possible to the real
DOM tree.
Creates a virtual DOM node. It can be used to render regular DOM elements:
createElement(tagName, attributes, ...children);
To render, pass the virtual node to the render
function:
render(
e('div', { className: 'kittens' }, e('h1', null, ' Nora')),
document.body
);
Which renders:
<div class="kittens">
<h1>Nora</h1>
</div>
It can also render function components:
createElement(functionComponent, props, ...children);
const Kitten = ({ name }) => {
return e('div', { className: 'kitten' }, e('h1', null, name));
};
render(
e('div', { className: 'kittens' }, e(Kitten, { name: 'Nora' })),
document.body
);
Which renders:
<div class="kittens">
<div class="kitten">
<h1>Nora</h1>
</div>
</div>
Use onClick
, onInput
or onSubmit
props:
const Kitten = ({ name }) => {
return e(
'div',
{ className: 'kitten' },
e('h1', null, name),
e('button', { onClick: () => console.log(`${name} woke up!`) }, 'Wake up')
);
};
render(
e('div', { className: 'kittens' }, e(Kitten, { name: 'Nora' })),
document.body
);
Which renders:
<div class="kittens">
<div class="kitten">
<h1>Nora</h1>
<button>Wake up</button>
</div>
</div>
Pressing the button will print Nora woke up!
to the console.
Adds local state to the component and provides a setter to update the state. Calling the setter triggers a rerender of the component subtree:
const Kitten = ({ name }) => {
const [isAwake, setIsAwake] = useState(false);
return e(
'div',
{ className: 'kitten' },
e('h1', null, name),
e('button', { onClick: () => setIsAwake(true) }, 'Wake up'),
isAwake && e('span', null, `${name} woke up!`)
);
};
render(
e('div', { className: 'kittens' }, e(Kitten, { name: 'Nora' })),
document.body
);
Which renders:
<div class="kittens">
<div class="kitten">
<h1>Nora</h1>
<button>Wake up</button>
</div>
</div>
Pressing the button will update the DOM to:
<div class="kittens">
<div class="kitten">
<h1>Nora</h1>
<button>Wake up</button>
<span>Nora woke up!</span>
</div>
</div>
Calls callback
whenever the dependencies array changes after the current
component render. Useful for running side effects during render:
const Kitten = ({ name }) => {
const [isAwake, setIsAwake] = useState(false);
useEffect(() => {
console.log(isAwake ? `${name} woke up!` : `${name} is asleep`);
}, [isAwake]);
return e(
'div',
{ className: 'kitten' },
e('h1', null, name),
e('button', { onClick: () => setIsAwake(true) }, 'Wake up')
);
};
render(
e('div', { className: 'kittens' }, e(Kitten, { name: 'Nora' })),
document.body
);
Which renders:
<div class="kittens">
<div class="kitten">
<h1>Nora</h1>
<button>Wake up</button>
</div>
</div>
On first render, the component prints Nora is asleep
to the console.
Pressing the button will print Nora woke up!
to the console. Future button
presses will not trigger the effect since we added isAwake
to the dependency
array.