The path from JavaScript to actual DOM elements appearing in your HTML document is not complex thanks to React. However, it is worth reviewing so that there is no mystery about it.
In this article, you will review how to use React.createElement
to get what you want into React’s virtual DOM so that React will convert into real DOM. There are three steps:
createElement
to build the “element tree”render
to let React build its virtual DOMThis article’s goal is for React to create the following HTML in the DOM.
<ul>
<li class="selected">
<a href="/pets">Pets</a>
</li>
<li>
<a href="/owners">Owners</a>
</li>
</ul>
There is one method to consider when building interfaces using low-level React. From the documentation, the React.createElement
function has the following form:
The arguments for it are
For each tag that you want to create with React, you will make a call to React.createElement
. In the HTML above, there are five tags to create:
ul
elementli
elementsa
elementsThree of those tags have attributes that you want to have appear in the DOM:
li
element has a “class” attribute (which you must translate to “className” when using in React)a
elements have “href” attributesFinally, there is a parent-child relationship between the elements.
ul
element is the parent of both li
elementsli
elements have a single a
element childa
elements have “child” text contentTo summarize, here are the elements and how you would translate them to their respective arguments for React.createElement
.
HTML snippet | type | props | children |
---|---|---|---|
<ul>...</ul> |
'ul' |
null |
Two calls to React.createElement , one for each li child |
<li class="selected">...</li> |
'li' |
{ className: 'selected' } |
One call to React.createElement for the a child |
<li>...</li> |
'li' |
null |
One call to React.createElement for the a child |
<a href="/pets">Pets</a> |
'a' |
{ href: '/pets' } |
The string 'Pets' |
<a href="/owners">Owners</a> |
'a' |
{ href: '/owners' } |
The string 'Owners' |
To create this tree of elements, you will use nested calls to React.createElement
. The standard formatting for this is for elements to have children, put each argument on its own line, and for elements that have no children or just text content, put all arguments on a single line.
Since the ul
has children, it will have its arguments on separate lines. Referring to the table above gives you:
The first li
element has a child. Its call to React.createElement
will have its arguments each go on their own separate lines:
React.createElement(
'ul',
null,
React.createElement(
'li',
{ className: 'selected' },
// a child
),
// Second li child,
);
The anchor element for “Pets” has only one text child. Its call to React.createElement
will have its arguments on one line:
React.createElement(
'ul',
null,
React.createElement(
'li',
{ className: 'selected' },
React.createElement('a', { href: '/pets'}, 'Pets'),
),
// Second li child,
);
The second li
element has a child. Its call to React.createElement
will have its arguments each go on their own separate lines:
React.createElement(
'ul',
null,
React.createElement(
'li',
{ className: 'selected' },
React.createElement('a', { href: '/pets'}, 'Pets'),
),
React.createElement(
'li',
null,
// a child
),
);
The other anchor element, the one for “Owners” has only one text child. Its call to React.createElement
will have its arguments on one line:
React.createElement(
'ul',
null,
React.createElement(
'li',
{ className: 'selected' },
React.createElement('a', { href: '/pets'}, 'Pets'),
),
React.createElement(
'li',
null,
React.createElement('a', { href: '/owners'}, 'Owners'),
),
);
That’s how you translate what you want from simple HTML into well-formatted calls to React.createElement
. That will build the “element tree” for React to use.
To tell React to start the conversion process, you have to use the React.render
method which takes a value returned from React.createElement
and a DOM node in the actual document where React will insert the result of the conversion into real DOM.
If you wanted to insert what was created in the last section into the main
tag, the most forward way of doing that is like this.
// Put the element tree in a variable
const navList = React.createElement(
'ul',
null,
React.createElement(
'li',
{ className: 'selected' },
React.createElement('a', { href: '/pets'}, 'Pets'),
),
React.createElement(
'li',
null,
React.createElement('a', { href: '/owners'}, 'Owners'),
),
);
// Get a DOM node for React to render to
const mainElement = document.querySelector('main');
// Give React the element tree and the target
ReactDOM.render(navList, mainElement);
At this point, you have given the element tree that you want created to React. It will then take that and construct its virtual DOM from it.
Now that it has built it’s own model of the virtual DOM using the elements that you created, it can now take that and turn that into real DOM.
It takes that real DOM and inserts it as the content of the target that you gave it which, in this case, is the main
element in the body of the document.
When you call React.render
again for the same component and target, React takes the existing virtual DOM it knows about last time it rendered the element tree, compares it to whatever new thing you want to render, and determines which (if any) of the living DOM needs to change.
For example, let’s say you constructed the same element tree but left off the “selected” class for the first list element. Then, when you rendered it, again, by calling React.render
, React would compare the new element tree with the old element tree, figure out that one class was missing on that one li
element, and remove that and only that from the real DOM.
In this article, you learned
React.createElement