Building a React-Like Library: Functional Components
This is the second of four issues where we build a React-like library to learn how React works under the hood.
Building a React-Like Library
The series contains the following articles:
Functional Components. This issue.
Video
If you prefer, I recorded a live-coding video explaining this article. Feel free to complement this article with it, or go and watch that instead.
Introduction
In the previous article, we built a site from a static virtual DOM. You can find the code in this gist.
const render = (vnode, parent) => {
// manage string type
if (typeof vnode === "string") {
return parent.appendChild(document.createTextNode(vnode));
}
// create HTML element
const element = document.createElement(vnode.tag);
// set attributes
if (vnode.props) {
Object.keys(vnode.props).forEach(key => {
const value = vnode.props[key];
element.setAttribute(key, value);
});
}
// iterate over children and render them
if (vnode.children) {
vnode.children.forEach(child => render(child, element));
}
// append the element created
return parent.appendChild(element);
};
const vDom = {
tag: "div",
props: {},
children: [
{
tag: "h1",
props: { id: "title" },
children: ["Hello, World!"]
},
{
tag: "p",
props: {},
children: ["I'm learning about virtual DOM"]
}
]
};
render(vDom, document.getElementById("root"));Build a Node With a Function
A node is an object with tag, props, and children:
{
tag: “h1”,
props: { id: “title” },
children: ["Hello, World!"]
}
// or
{
tag: "div",
props: {},
children: [...]
}Let’s build the node with a function.
const createElement = (tag, props, children) => ({ tag, props, children });Let’s use this function:
const node = createElement(“h1”, { id: “title” }, [“Hello from app!”]);Building the Virtual DOM With a Function
To create all the virtual DOM with createElement, all the children nodes need to be created also with createElement:
const vDom = createElement(
"div",
{},
[
createElement("h1", {}, ["Hello from app!"]),
createElement("p", {}, ["This was built with createElement"])
]
);That’s it; now our vDom is the same as before, but we built it with the function createElement. Which is similar to what React does with React.createElement.
Functional Components
One of the main features of React is the functional components. Let’s refactor the h1 to be a functional component:
const Title = () => createElement("h1", {}, ["Hello from dynamic app!"]);Our virtual DOM now has a functional component:
Let’s build our vDom again:
const vDom = createElement(
"div",
{},
[
// Functional component
createElement(Title, {}, []),
// createElement("h1", {}, ["Hello from app!"])
createElement("p", {}, ["This was built with createElement"])
]
);Render Function With Functional Components
Notice how now one node uses the functional component;
createElement(Title, {}, []),The render function doesn’t know what to do with a “tag” that is a function. It can only handle tags as strings:
const render = (vnode, parent) => {
//…
// create HTML element
const element = document.createElement(vnode.tag);
//…
}This “tag” function is our functional component, which returns a node when called:
const Title = () => createElement("h1", {}, ["Hello from dynamic app!"]);We call the “tag” function and pass the returned value (another node) to the render function:
const render = (vnode, parent) => {
// ...
// manage function type
if (typeof vnode.tag === "function") {
// call function to get the virtual DOM node
const nextVnode = vnode.tag();
return render(nextVnode, parent);
}
// ...
}And now it works! Our React-like “library” can now render functional components.
Put It Together
I recorded a live-coding video explaining this article. It might be helpful as a recap also.
Let’s take a look at it all together. First, our new virtual DOM:
const Title = () => createElement("h1", {}, ["Hello from dynamic app!"]);
const vDom = createElement(
"div",
{},
[
createElement(Title, {}, []),
createElement("p", {}, ["This was built with createElement"])
]
);Title is a functional component, but now our render function knows how to deal with functional components:
const render = (vnode, parent) => {
// manage string type
if (typeof vnode === "string") {
return parent.appendChild(document.createTextNode(vnode));
}
// manage functional component
if (typeof vnode.tag === "function") {
const nextVnode = vnode.tag();
render(nextVnode, parent);
return;
}
// create HTML element
const element = document.createElement(vnode.tag);
// set attributes
if (vnode.props) {
Object.keys(vnode.props).forEach(key => {
const value = vnode.props[key];
element.setAttribute(key, value);
});
}
// iterate over children and render them
if (vnode.children) {
vnode.children.forEach(child => render(child, element));
}
// append the element created
return parent.appendChild(element);
};Finally, we render the vDom into the website:
render(vDom, document.getElementById("root"));IMHO, the next issue is the most impressive. We’ll create interactive applications by adding state to the functional components (useState)! Stay tuned!
Thanks to Bernat and Sebastià for reviewing this article 🙏



