Updates to first chapter.

master
Thomas Hintz 4 years ago
parent bdc0b9cbb8
commit aa8ece3f0c

@ -1,3 +1,16 @@
#+BEGIN_SRC emacs-lisp :exports results :results silent
(require 'ox-latex)
(add-to-list 'org-latex-packages-alist '("" "minted"))
(setq org-latex-listings 'minted)
(setq org-latex-pdf-process
'("xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"))
#+END_SRC
# #+latex_class: article
# #+latex_class_options: [a4paper,8pt]
# #+latex_header: \usepackage[a4paper,top=2.5cm,bottom=2.5cm,left=1.5cm,right=1.5cm]{geometry}
# #+latex_header:\renewcommand{\baselinestretch}{1.2}
#+TITLE: High-Performance React #+TITLE: High-Performance React
#+AUTHOR: Thomas Hintz #+AUTHOR: Thomas Hintz
@ -87,7 +100,7 @@ Before baking is finished bread is a living organism. The way it grows
and develops and flavors depend on what you feed it and how you feed and develops and flavors depend on what you feed it and how you feed
it and massage it, care for it. If you have it grow and ferment at a it and massage it, care for it. If you have it grow and ferment at a
higher temperature and more yeast it overdevelops producing too much higher temperature and more yeast it overdevelops producing too much
alcohol. If you give it too much time acidity will take over the alcohol. If you give it too much time, acidity will take over the
flavor. The recipes I used initially were missing a critical flavor. The recipes I used initially were missing a critical
ingredient: the rising temperature. ingredient: the rising temperature.
@ -101,13 +114,14 @@ the other ingredients to complement the temperature. Now the bread can
tell me what to do. tell me what to do.
While React isn't technically a living organism that can tell us what While React isn't technically a living organism that can tell us what
to do it is, in its whole, a complex, abstract entity. We could learn basic to do, it is, in its whole, a complex, abstract entity. We could learn
recipes for how to write high-performance React code but they wouldn't basic recipes for how to write high-performance React code but they
apply in all cases and as React and things under it change our recipes wouldn't apply in all cases, and as React and things under it change
would fall out-of-date. So like the bread, to produce consistently our recipes would fall out-of-date. So like the bread, to produce
good results we need to understand how React does what it does. consistently good results we need to understand how React does what it
does.
** React, made of ** Components of React
Conceptually React is very simple. It starts by walking a tree of Conceptually React is very simple. It starts by walking a tree of
components and building up a tree of their output. Then it compares components and building up a tree of their output. Then it compares
@ -128,41 +142,43 @@ questions with solid answers.
React is centered around the ~render~ method. The ~render~ method is React is centered around the ~render~ method. The ~render~ method is
what walks our trees, diffs them with the browser's DOM tree, and what walks our trees, diffs them with the browser's DOM tree, and
updates the DOM as needed. But before we can look at the ~render~ updates the DOM as needed. But before we can look at the ~render~
method me have to understand its input. The input comes from method we have to understand its input. The input comes from
~createElement~. While ~createElement~ itself is unlikely to be a ~createElement~. While ~createElement~ itself is unlikely to be a
bottleneck it's a good to understand how it works so that we can have bottleneck it's good to understand how it works so that we can have a
a complete picture of the entire process. The more black-boxes we have complete picture of the entire process. The more black-boxes we have
in our mental model the harder it will be for us to diagnose in our mental model the harder it will be for us to diagnose
performance problems. performance problems.
** Markup in Javascript: ~JSX~ ** Markup in JavaScript: ~JSX~
~createElement~, however, takes as input something that is probably ~createElement~, however, takes as input something that is probably
not familiar to us since we usually work in JSX, which is the last 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 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 it. While not strictly a part of React, it is almost universally used
with it. And if we understand it then ~createElement~ will be less of with it. And if we understand it then ~createElement~ will be less of
a mystery since we will be able to connect all the dots. a mystery since we will be able to connect all the dots.
JSX is not valid HTML or Javascript but its own language compiled by a JSX is not valid HTML or JavaScript but its own language compiled by a
compiler, like Babel. The output of that compilation is valid compiler, like Babel. The output of that compilation is valid
Javascript that represents the original markup. JavaScript that represents the original markup.
Before JSX the normal way of injecting HTML into the DOM was via Before JSX or similar compilers, the normal way of injecting HTML into
directly utilizing the browser's DOM APIs. This was very cumbersome. the DOM was via directly utilizing the browser's DOM APIs or by
The code's structure did not match the structure of the HTML that it setting ~innerHTML~. This was very cumbersome. The code's structure
output which made it hard to quickly understand what the output of did not match the structure of the HTML that it output which made it
a piece of code would be. So naturally programmers have been endlessly hard to quickly understand what the output of a piece of code would
searching for better ways to mix HTML with Javascript. 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 And this brings us to JSX. It is nothing new; nothing
complicated. Forms of it have been made and used long before React 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. adopted it. Now let's see if we can discover JSX for ourselves.
To start with we need to create a data structure that both represents To start with, we need to create a data-structure -- let's call it
a DOM tree and can also be used to insert one into the browser's JavaScript Markup (JSM) -- that both represents a DOM tree and can
DOM. And to do that we need to understand what a tree of DOM nodes is also be used to insert one into the browser's DOM. And to do that we
constructed of. What parts do you see here? need to understand what a tree of DOM nodes is constructed of. What
parts do you see here?
#+BEGIN_SRC html #+BEGIN_SRC html
<div class="header"> <div class="header">
@ -174,26 +190,21 @@ constructed of. What parts do you see here?
I see three parts: the name of the tag, the tag's properties, and its I see three parts: the name of the tag, the tag's properties, and its
children. children.
|----------+-----------------------------| |-----------+-----------------------------|
| name | 'div', 'h1', 'input' | | Name: | 'div', 'h1', 'input' |
| props | 'class', 'type', 'disabled' | | Props: | 'class', 'type', 'disabled' |
| children | <h1>, <input>, Hello | | Children: | <h1>, <input>, Hello |
#+BEGIN_SRC
tag name: 'div'
tag prop: 'class'
children: h1..., 'Hello', input...
#+END_SRC
Now how could we recreate that in Javascript? Now how could we recreate that in JavaScript?
In Javascript we store lists of things in arrays and key/value In JavaScript, we store lists of things in arrays, and key/value
properties in objects. Luckily for us Javascript even gives us literal 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 syntax for both so we can easily make a compact DOM tree with our own
notation. notation.
This is what I'm thinking: This is what I'm thinking:
#+CAPTION: JSM - JavaScript Markup
#+BEGIN_SRC javascript #+BEGIN_SRC javascript
['div', { 'className': 'header' }, ['div', { 'className': 'header' },
[['h1', {}, ['Hello']], [['h1', {}, ['Hello']],
@ -202,11 +213,11 @@ This is what I'm thinking:
] ]
#+END_SRC #+END_SRC
As you can see we have a clear mapping from our notation to the As you can see in, we have a clear mapping from our notation, JSM, to
original HTML. Our tree is made up of three element arrays. The first the original HTML. Our tree is made up of three element arrays. The
item in the array is the tag, the second is an object containing the first item in the array is the tag, the second is an object containing
tag's properties, and the third is an array of its children; which are the tag's properties, and the third is an array of its children; which
all made up of the same three element arrays. are all made up of the same three element arrays.
The truth is though, if you stare at it long enough, although the The truth is though, 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 mapping is clear, how much fun would it be to read and write that on a
@ -224,7 +235,7 @@ 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 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 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 you look back to our notation you can see that you can easily embed
arbitrary Javascript expressions wherever you want in a node. As you arbitrary JavaScript expressions wherever you want in a node. As you
may have realized, that's exactly what the JSX compiler does when it may have realized, that's exactly what the JSX compiler does when it
sees curly braces! sees curly braces!
@ -232,7 +243,7 @@ There are three main differences between our data structure and the
real one that the JSX compiler outputs: it uses objects instead of real one that the JSX compiler outputs: it uses objects instead of
arrays, it inserts calls to React.createElement on children, and arrays, it inserts calls to React.createElement on children, and
spreads the children instead of containing them in an array. Here is spreads the children instead of containing them in an array. Here is
what "real" JSX compiler output looks like: what real JSX compiler output looks like:
# #+NAME: foo # #+NAME: foo
# #+CAPTION: foo bar # #+CAPTION: foo bar
@ -248,10 +259,10 @@ React.createElement(
); );
#+END_SRC #+END_SRC
As you can see it is very similar to our data-structure and for the As you can see, it is very similar to our markup data-structure and
purposes of this book we will use our own simplified data-structure as for the purposes of this book we will use our own simplified
it's a bit easier to work with. A JSX compiler also does some data-structure as it's a bit easier to work with. A JSX compiler also
validation and escapes input to prevent cross-site scripting does some validation and escapes input to prevent cross-site scripting
attacks. In practice though they would behave the same in the ways attacks. In practice though they would behave the same in the ways
that matter to us now. that matter to us now.
@ -266,7 +277,7 @@ achieve that objective. ~createElement~ will take as input our
JSX-like notation and output a tree of objects compatible with JSX-like notation and output a tree of objects compatible with
~render~. ~render~.
React expects nodes defined as Javascript objects that look like this: React expects nodes defined as JavaScript objects that look like this:
#+BEGIN_SRC javascript #+BEGIN_SRC javascript
{ {

@ -4,31 +4,31 @@ Baking bread. When I first began to learn how to bake bread the recipe told me w
Understanding: that's what I was missing. The bread I make is now consistently good. The recipes I use are simpler and only give ratios and general recommendations for rests and waits. So why does the bread turn out better? Understanding: that's what I was missing. The bread I make is now consistently good. The recipes I use are simpler and only give ratios and general recommendations for rests and waits. So why does the bread turn out better?
Before baking is finished bread is a living organism. The way it grows and develops and flavors depend on what you feed it and how you feed it and massage it, care for it. If you have it grow and ferment at a higher temperature and more yeast it overdevelops producing too much alcohol. If you give it too much time acidity will take over the flavor. The recipes I used initially were missing a critical ingredient: the rising temperature. Before baking is finished bread is a living organism. The way it grows and develops and flavors depend on what you feed it and how you feed it and massage it, care for it. If you have it grow and ferment at a higher temperature and more yeast it overdevelops producing too much alcohol. If you give it too much time, acidity will take over the flavor. The recipes I used initially were missing a critical ingredient: the rising temperature.
But unlike a lot of ingredients: temperature is hard to control for the home cook. So the recipe can't just tell you exactly what temperature to grow the bread at. My initial recipes just silently made assumptions for the temperature, which rarely turn out to be true. This means that the only way to consistently make good bread is to have an understanding of how bread develops so that you can adjust the other ingredients to complement the temperature. Now the bread can tell me what to do. But unlike a lot of ingredients: temperature is hard to control for the home cook. So the recipe can't just tell you exactly what temperature to grow the bread at. My initial recipes just silently made assumptions for the temperature, which rarely turn out to be true. This means that the only way to consistently make good bread is to have an understanding of how bread develops so that you can adjust the other ingredients to complement the temperature. Now the bread can tell me what to do.
While React isn't technically a living organism that can tell us what to do it is, in its whole, a complex, abstract entity. We could learn basic recipes for how to write high-performance React code but they wouldn't apply in all cases and as React and things under it change our recipes would fall out-of-date. So like the bread, to produce consistently good results we need to understand how React does what it does. While React isn't technically a living organism that can tell us what to do, it is, in its whole, a complex, abstract entity. We could learn basic recipes for how to write high-performance React code but they wouldn't apply in all cases, and as React and things under it change our recipes would fall out-of-date. So like the bread, to produce consistently good results we need to understand how React does what it does.
## React, made of ## Components of React
Conceptually React is very simple. It starts by walking a tree of components and building up a tree of their output. Then it compares that tree to the tree currently in the browser's DOM to find any differences between them. When it finds differences it updates the browser's DOM to match its internal tree. Conceptually React is very simple. It starts by walking a tree of components and building up a tree of their output. Then it compares that tree to the tree currently in the browser's DOM to find any differences between them. When it finds differences it updates the browser's DOM to match its internal tree.
But what does that actually look like? If your app is janky does that explanation point you towards what is wrong? No. It might make you wonder if maybe it is too expensive to re-render the tree or if maybe the diffing React does is slow but you won't really know. When I was initially testing out different bread recipes I had guesses at why it wasn't working but I didn't really figure it out until I had a deeper understanding of how making bread worked. It's time we build up our understanding of how React works so that we can start to answer our questions with solid answers. But what does that actually look like? If your app is janky does that explanation point you towards what is wrong? No. It might make you wonder if maybe it is too expensive to re-render the tree or if maybe the diffing React does is slow but you won't really know. When I was initially testing out different bread recipes I had guesses at why it wasn't working but I didn't really figure it out until I had a deeper understanding of how making bread worked. It's time we build up our understanding of how React works so that we can start to answer our questions with solid answers.
React is centered around the `render` method. The `render` method is what walks our trees, diffs them with the browser's DOM tree, and updates the DOM as needed. But before we can look at the `render` method me have to understand its input. The input comes from `createElement`. While `createElement` itself is unlikely to be a bottleneck it's a good to understand how it works so that we can have a complete picture of the entire process. The more black-boxes we have in our mental model the harder it will be for us to diagnose performance problems. React is centered around the `render` method. The `render` method is what walks our trees, diffs them with the browser's DOM tree, and updates the DOM as needed. But before we can look at the `render` method we have to understand its input. The input comes from `createElement`. While `createElement` itself is unlikely to be a bottleneck it's good to understand how it works so that we can have a complete picture of the entire process. The more black-boxes we have in our mental model the harder it will be for us to diagnose performance problems.
## Markup in Javascript: `JSX` ## 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 then `createElement` will be less of a mystery since we will be able to connect all the dots. `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 then `createElement` will be less of a mystery since we will 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. 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 the normal way of injecting HTML into the DOM was via directly utilizing the browser's DOM APIs. 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. Before JSX or similar compilers, the normal 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. 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 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? 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"} {format: "html"}
``` ```
@ -40,23 +40,17 @@ To start with we need to create a data structure that both represents a DOM tree
I see three parts: the name of the tag, the tag's properties, and its children. I see three parts: the name of the tag, the tag's properties, and its children.
| name | 'div', 'h1', 'input' | | Name: | 'div', 'h1', 'input' |
| props | 'class', 'type', 'disabled' | | Props: | 'class', 'type', 'disabled' |
| children | <h1>, <input>, Hello | | Children: | <h1>, <input>, Hello |
``` Now how could we recreate that in JavaScript?
tag name: 'div'
tag prop: 'class'
children: h1..., 'Hello', input...
```
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.
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: This is what I'm thinking:
{format: "javascript"} {format: "javascript", caption: "JSM - JavaScript Markup"}
``` ```
['div', { 'className': 'header' }, ['div', { 'className': 'header' },
[['h1', {}, ['Hello']], [['h1', {}, ['Hello']],
@ -65,15 +59,15 @@ This is what I'm thinking:
] ]
``` ```
As you can see we have a clear mapping from our notation 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. As you can see in, 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 though, 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 rather 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. We will get back to this. The truth is though, 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 rather 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. We will get back to this.
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. 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 arbitrary Javascript expressions wherever you want in a node. As you may have realized, that's exactly what the JSX compiler does when it sees curly braces! 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 arbitrary JavaScript expressions wherever you want in a node. As you may have realized, that's exactly what the JSX compiler does when it sees curly braces!
There are three main differences between our data structure and the real one that the JSX compiler outputs: 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: There are three main differences between our data structure and the real one that the JSX compiler outputs: 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"} {format: "javascript"}
``` ```
@ -87,7 +81,7 @@ React.createElement(
); );
``` ```
As you can see it is very similar to our data-structure and for the purposes of this book we will use our own simplified data-structure 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 they would behave the same in the ways that matter to us now. As you can see, it is very similar to our markup data-structure and for the purposes of this book we will use our own simplified data-structure 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 they would behave the same in the ways that matter to us now.
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. 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.
@ -95,7 +89,7 @@ So now that we've worked through JSX we're ready to tackle `createElement`, the
React's `render` expects to consume a tree of element objects in a specific, uniform format. `createElement` is the method by which we achieve that objective. `createElement` will take as input our JSX-like notation and output a tree of objects compatible with `render`. React's `render` expects to consume a tree of element objects in a specific, uniform format. `createElement` is the method by which we achieve that objective. `createElement` will take as input our JSX-like notation and output a tree of objects compatible with `render`.
React expects nodes defined as Javascript objects that look like this: React expects nodes defined as JavaScript objects that look like this:
{format: "javascript"} {format: "javascript"}
``` ```

Loading…
Cancel
Save