You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

70 lines
4.7 KiB
Plaintext

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Markup in JavaScript: JSX
`createElement`, however, takes as input something that is probably not familiar to us since we usually work in JSX, which is the last element of the chain in this puzzle and the first step in solving it. While not strictly a part of React, it is almost universally used with it. And if we understand it, `createElement` will then be less of a mystery since well be able to connect all the dots.
JSX is not valid HTML or JavaScript but its own language compiled by a compiler, like Babel. The output of that compilation is valid JavaScript that represents the original markup.
Before JSX or similar compilers, the typical way of injecting HTML into the DOM was via directly utilizing the browser's DOM APIs or by setting `innerHTML`. This was very cumbersome. The code's structure did not match the structure of the HTML that it output which made it hard to quickly understand what the output of a piece of code would be. So naturally programmers have been endlessly searching for better ways to mix HTML with JavaScript.
And this brings us to JSX. It is nothing new, nothing complicated. Forms of it have been made and used long before React adopted it. Now let's see if we can discover JSX for ourselves.
To start with, we need to create a data-structure let's call it JavaScript Markup (JSM) that both represents a DOM tree and can also be used to insert one into the browser's DOM. And to do that we need to understand what a tree of DOM nodes is constructed of. What parts do you see here?
{format: "html"}
```
<div class="header">
<h1>Hello</h1>
<input type="submit" disabled />
</div>
```
I see three parts: the name of the tag, the tag's properties, and its children.
| Name: | 'div', 'h1', 'input' |
| Props: | 'class', 'type', 'disabled' |
| Children: | <h1>, <input>, Hello |
Now how could we recreate that in JavaScript?
In JavaScript, we store lists of things in arrays, and key/value properties in objects. Luckily for us, JavaScript even gives us literal syntax for both so we can easily make a compact DOM tree with our own notation.
This is what I'm thinking:
{format: "javascript", caption: "JSM - JavaScript Markup"}
```
['div', { 'className': 'header' },
[['h1', {}, ['Hello']],
['input', { 'type': 'submit', 'disabled': 'disabled' },
[]]
]
]
```
As you can see, we have a clear mapping from our notation, JSM, to the original HTML. Our tree is made up of three element arrays. The first item in the array is the tag, the second is an object containing the tag's properties, and the third is an array of its children which are all made up of the same three element arrays.
The truth is, if you stare at it long enough, although the mapping is clear, how much fun would it be to read and write that on a consistent basis? I can assure you, it is not fun. But it has the advantage of being easy to insert into the DOM. All you need to do is write a simple recursive function that ingests our data structure and updates the DOM accordingly. Well get back to that.
So now we have a way to represent a tree of nodes and we (theoretically) have a way to get those nodes into the DOM. But if we are being honest with ourselves, while functional, it isn't a pretty notation nor easy to work with.
And this is where our object of study enters the scene. JSX is just a notation that a compiler takes as input and outputs in its place a tree of nodes nearly identical to the notation we came up with! And if you look back to our notation you can see that you can easily embed in a node arbitrary JavaScript expressions wherever you want. As you may have realized, that's exactly what the JSX compiler does when it sees curly braces!
There are three main differences between JSM and the real output of the JSX compiler: it uses objects instead of arrays, it inserts calls to React.createElement on children, and spreads the children instead of containing them in an array. Here is what real JSX compiler output looks like:
{format: "javascript"}
```
React.createElement(
'div',
{ className: 'header' },
React.createElement('h1', {}, 'Hello'),
React.createElement(
'input',
{ type: 'submit', 'disabled': 'disabled' })
);
```
As you can see, it is very similar to our JSM data-structure and, for the purposes of this book, well use JSM, as it's a bit easier to work with. A JSX compiler also does some validation and escapes input to prevent cross-site scripting attacks. In practice though, it would behave the same in our areas of study and well keep things simple by leaving out those aspects of the JSX compiler.
So now that we've worked through JSX we're ready to tackle `createElement`, the next item on our way to building our own React.