(no title)
efortis | 1 month ago
function render() {
restoreFocus(() =>
document.body.replaceChildren(App()))
}
function App() {
return (
createElement('div', { className: 'App' },
createElement('h1', null, 'Hello, World')))
}
function createElement(tag, props, ...children) {
const elem = document.createElement(tag)
for (const [k, v] of Object.entries(props || {}))
if (k === 'ref') v.elem = elem
else if (k === 'style') Object.assign(elem.style, v)
else if (k.startsWith('on')) elem.addEventListener(k.slice(2).toLowerCase(), ...[v].flat())
else if (k in elem) elem[k] = v
else elem.setAttribute(k, v)
elem.append(...children.flat().filter(Boolean))
return elem
}
`restoreFocus` is here:https://github.com/ericfortis/mockaton/blob/main/src/client/...
Results so far:
Rendering the whole DOM tree (instead of VDOMs) is a fast process. The slow part is attaching (committing) elements to the doc. For example, I have a test of 20,000 elements which takes <30ms to render, while attaching them takes 120ms.
Since the performance is mainly bound to the commit phase, with a DOM merging library, or hopefully, if we get a native API such as `document.replaceChildren(...App(), { merge: true })`, this approach could be better.
Caveats:
Although it restores focus, that's not the only thing we need to preserve, we also need to preserve scroll position and cursor position.
So to work around that, I still have to step out fully declarative, by just replacing the part that changed. For example, here I had to do manually mutate the DOM:
https://github.com/ericfortis/mockaton/blob/main/src/client/...
my_throwaway23|1 month ago
efortis|1 month ago
https://react.dev/reference/react/createElement