React-in-Choo
This document will describe how to render React code in Choo. To understand how React can be rendered inside of Choo, we must first understand how Choo renders, and then how React renders.
On Choo rendering
If you navigate to a page, and index.html
loads, then the events that are emitted are
DOMContentLoaded
render
For a page load, the page can be seen as being rendered "twice", once is loading the DOM, and next would be mounting Choo's functionality into the DOM. This means that if you render React in DOMContentLoaded, your changes will be overwritten by the render event for Choo.
If you navigate to a page, and then navigate to a page, then the events are different and are instead:
render
pushState
navigate
If we want to load React into Choo, then the event render is mainly what we're interested in, and this is where we would need to load React into it.
Mouting and unmounting React into Choo
Rendering React into Choo is pretty simple. If we're loading a new page, we need this
emitter.on("DOMContentLoaded", () => {
state.initialRoute = state.route
})
and then to render and unmount React, we need an MutationObserver
emitter.on("render", () => {
if (state.route !== "route" && state.root) {
state.root.unmount()
state.root = undefined
}
if (state.route === "route") {
if (state.initialRoute === "route") {
state.root = createRoot(document.getElementById("react-root"));
state.root.render(<Root />);
state.initialRoute = undefined
} else {
const callback = (mutationList, observer) => {
for (const mutation of mutationList) {
mutation.addedNodes.forEach((node) => {
if (node.id == id) {
if (!state.root) {
state.root = createRoot(document.getElementById("react-root"));
}
state.root.render(<Root />);
}
})
}
};
const observer = new MutationObserver(callback);
const config = { childList: true, subtree: true };
observer.observe(document.getElementById("choo-root"), config);
}
}
})
Because Choo doesn't have an event that is emitted when rendering is completed, we instead watch the DOM and wait until the "empty div" is rendered, and that's where we would render the React into. React can render into any element, so all we really need is the guarantee that an Element exists, and we load React into it. Of course, in the case that the Choo page is interactive, that can lead to weird behaviours and the React loaded would instead be a stateful Choo components, but otherwise it's fine as is.