Enea Xharja Logo

⚛️ JSX and the virtual DOM

One of the things that distinguish React, from earlier front-end JavaScript frameworks, is the Virtual DOM. The Virtual DOM is a virtual representation of the DOM, and it can be described as a tree of JavaScript objects that represent the "real DOM". When we work in React, we must manipulate the virtual representation of the DOM and let React handle the changes on the browser's DOM.

One thing that comes to mind is why should we create the virtual DOM instead of modifying the actual one. In fact, this is what we do constantly when working with jQuery or vanilla JavaScript. We usually select an element (i.e. document.querySelector()) and then modify that element directly.

This approach is still valid and is used daily by lots of developers, however is presents some problems that the React team has managed to fix thanks to the implementation of the Virtual DOM.

The main problems that raise when targeting the actual DOM are two:

  • it becomes hard to keep track of changes like, current and previous state of the DOM;
  • modifying the actual DOM on every change is costly and can cause significant performance issues.

Thus, the Virtual DOM was created to solve these problems.

The Virtual DOM

The Virtual DOM is a tree of ReactElements, where a ReactElement is just a representation of a DOM element in the Virtual DOM. Once we create ReactElements, React places them into the real DOM.

In order to create a ReactElement, we use the React method createElement. Once we have the element, it will not be visible without giving it to React to render in the actual DOM tree.

Finally, to render the element, we use ReactDOM.render(), which requires two things:

  • what we want to render (i.e. b tag)
  • where do we want to render it
1var boldElement = React.createElement('b');
2var mountElement = document.querySelector('#root');
3
4ReactDOM.render(boldElement, mountElement);

Adding Text (with children)

Now that we rendered a tag in the DOM, we want to add also some content inside of it, for instance some text. Text is located in-between the opening and closing b tags (), so it can be considered as its child.

Once again, we can use React.createElement() function, which accepts three arguments:

  • the DOM element type (i.e. the b tag we used above),
  • the element props (for now let's leave it as null),
  • the children of the element (must be a ReactNode object).

A ReactNode object can be any of the following:

  • ReactElement,
  • a string or a number (a ReactText object)
  • an array of ReactNodes
1var boldElement = React.createElement('b', null, "Some text (as a string)");
2var mountElement = document.querySelector('#root');
3
4ReactDOM.render(boldElement, mountElement);

The function ReactDOM.render() can do much more than this. We can use it to render components not only on the DOM, but also in other frameworks such as mobile apps.

JSX

If we have to deal with small components, React.createElement works just fine. However, if we have many nested components, the syntax can become complicated and difficult to read.

The idea behind JSX (JavaScript Syntax Extension) is to represent our React component tree using markup, just like we would do in HTML. For instance, we use HTML to describe pages to our browser. Then, the HTML is parsed by the browser in order to create HTML Elements which will become the actual DOM.

The JSX parser will read that string that we want to use and it will handle React.createElement for us:

1var boldElement = <b>Some text</b>;

As we can see from the example above, JSX syntax is very similar to HTML/XML; with the exception that it allows us to create our own tags. Moreover, we often surround JSX with parenthesis, in order to distinguish it from pure JavaScript and use uppercase letter, in contrast to the lowercase letter used in HTML. Plus, we can add logic to a view, by mixing JavaScript with JSX markup.

1const Message = (props) => (
2 <div>
3 {prop.text}
4 </div>
5)

When using JSX, there is one thing that we need to keep in mind: browsers don't know how to read JSX. For this reason, we must pass our code through a compiler (like Babel), which will transform our code into JavaScript (transpiled code).

Let's see now a bunch of examples on how we can use JSX in our code.

JSX Attribute Expressions

1const warningLevel = 'debug';
2
3const component = (
4 <Alert
5 color={warningLevel === 'debug' ? 'gray' : 'red'}
6 log={true}
7 />
8)

If the warningLevel variable is set to debug, then the color prop will be 'gray', otherwise it will be 'red'.

JSX Conditional Child Expressions

We can use a boolean checking expression and then render an element conditionally.

1const Menu = (
2 <ul>
3 {loggedInUser ? <UserMenu /> : <LoginLink />}
4 </ul>
5)

If the user is logged in, then the UserMenu will be rendered; otherwise the LoginLink we be shown.

JSX Boolean Attributes

We need to pass a true or false explicitly as an attribute:

1<input name='Name' disabled={true} />

or

1let formDisabled = true;
2
3<input name='Name' disabled={formDisabled} />

JSX Comments

We can define comments inside of JSX by using the curly braces ({}) with comment delimiters (/* */):

1let userLevel = 'admin';
2{/* Show the admin menu if the userLevel is 'admin' */}
3{userLevel === 'admin' && <AdminMenu />}

JSX Spread Syntax

Sometimes when we have many props to pass to a component, it can be cumbersome to list each one individually.

1const props = {
2 msg: "Hello",
3 recipient: "World"
4}
5
6<Component
7 {...props}
8/>

which is the same of doing:

1<Component
2 msg={"Hello"}
3 recipient={"World"}
4/>

When using JSX, there are some things that we need to keep in mind:

  • class vs className

considering that JSX is tied to JavaScript, class is a reserved word. That's why we use className, which expects to receive a string that identifies the class (or classes) associated with a CSS class.

1<div className='box'></div>
  • for and htmlFor

For the same reason we cannot use the class attribute, we cannot apply the for attribute to a <label> element. we must use the attribute htmlFor.

1<label htmlFor='email'>Email</label>
2<input name='email' type='email' />
  • HTML Entities and Emoji

Entities are reserved characters in HTML which include characters such as less-than <, greater-than >, the copyright symbol, etc. In order to display entities, we can just place the entity code in literal text.

1<ul>
2 <li>phone: &phone;</li>
3 <li>star: &star;</li>
4</ul>

or instead of using the entity character code, we can use unicode version instead:

1return (
2 <ul>
3 <li>phone: {'\u0260e'}</li>
4 <li>star: {'\u2606'}</li>
5 </ul>
6)
  • data-anything

There are a standard set of web accessibility attributes and its a good idea to use them because there are many people who will have a hard time using our site without them.

1<div aria-hidden={true} />

The key thing to keep in mind is that JSX is syntactic sugar to call React.createElement. JSX is a convenience syntax to help build the component tree.

Notes from Fullstack React Book