Edits to the first chapter.

master
Thomas Hintz 4 years ago
parent 66faaa4efe
commit 2dd5e879af

@ -56,7 +56,7 @@ the method will remain the same.
TODO note that the book references React-DOM but the algorithms should
generally apply to all React implementations.
* Mini React
* Fundamentals: Building our own React
Baking bread. When I first began to learn how to bake bread the recipe
told me what to do. It listed some ingredients and told me how to
combine them and prescribed times of rest. It gave me an oven
@ -93,13 +93,13 @@ 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.
** Basic React
** React, made 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
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 tree.
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
@ -108,22 +108,31 @@ 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
understand of how React works so that we can start to answer our
understanding of how React works so that we can start to answer our
questions with solid answers.
React is made up of a few pieces: ~createElement~, ~render~, and
reconciliation. The first building block is ~createElement~. While
~createElement~ is itself 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.
** ~JSX~
But before we get to ~createElement~ we should talk about JSX. 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.
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.
** 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.
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.
@ -141,16 +150,6 @@ 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?
TODO include text element (Hello)
TODO change to using objects instead of arrays?
probably do after what we've already done
{
type: 'h1',
props: { x: y },
children: []
}
#+BEGIN_SRC html
<div class="header">
<h1>Hello</h1>
@ -159,7 +158,15 @@ probably do after what we've already done
#+END_SRC
I see three parts: the name of the tag, the tag's properties, and its
children. Now how could we recreate that in Javascript?
children.
#+BEGIN_SRC
tag name: 'div'
tag prop: 'class'
children: h1..., 'Hello', input...
#+END_SRC
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
@ -198,15 +205,15 @@ 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 expression 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
sees curly braces!
There are three main differences between our data structure and the
real one that 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:
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:
#+BEGIN_SRC javascript
React.createElement(
@ -221,15 +228,21 @@ 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. In practice they would behave the same
in the ways that matter to us now.
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 item on our way to building our own React.
~createElement~, the next item on our way to building our own React.
TODO JSX also does validation and escapes input to prevent XXS
** Getting Ready to Render with ~createElement~
** ~createElement~
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:
@ -245,20 +258,12 @@ React expects nodes defined as Javascript objects that look like this:
}
#+END_SRC
That is an object with two properties: ~type~ and ~props~. The ~props~
property contains all the properties of the node. The node's
That is: an object with two properties: ~type~ and ~props~. The
~props~ property contains all the properties of the node. The node's
~children~ are also considered part of its properties. The full
React's ~createElement~ includes more properties but they are unlikely
to be relevant to your application's performance or our version of
React here.
#+BEGIN_SRC javascript
// React's createElement
const ReactElement = function(type, key, ref, self, source, owner, props)
#+END_SRC
So all our ~createElement~ needs to do is transform our data structure
into the objects that our React expects.
version of React's ~createElement~ includes more properties but they
are unlikely to be relevant to your application's performance or our
version of React here.
#+BEGIN_SRC javascript
function createElement(node) {
@ -300,11 +305,10 @@ process of rendering our tree to the DOM!
** Render
There are now only two major puzzles remaining in our quest for our
own React. The next piece is: ~render~: how do we go from our tree of
own React. The next piece is: ~render~. How do we go from our tree of
nodes to actually displaying something on screen?
The signature for our ~render~ method is very simple and will be
familiar to you:
The signature for our ~render~ method should be familiar to you:
#+BEGIN_SRC javascript
function render(element, container)
@ -321,7 +325,12 @@ function render(element, container) {
container.appendChild(domElement);
#+END_SRC
TODO and now full code:
Our DOM element is created first. Then we set the properties, render
children elements, and finally append the whole tree to the
container. Now we will work on expanding the psuedocode until we build
our own fully functional ~render~ method using the same general
algorithm React uses. Next we will focus on the initial render and
ignore reconciliation.
#+BEGIN_SRC javascript
function render(element, container) {
@ -347,20 +356,17 @@ function render(element, container) {
}
#+END_SRC
Next, we look at renderDOMElement which must also set properties on
the newly created DOM element and render any children.
To start with we create the DOM element. Then we need to set its
We begin by creating the DOM element. Then we need to set its
properties. To do this we first need to filter out the ~children~
property and then we simply loop over they keys setting each property
directly. Then we render each of the children by looping over the
children recursively calling ~render~ on each with the ~container~ set
to the current DOM element (which is each child's parent).
Now we can go all the way from JSX to a rendered tree in the browser's
DOM! But so far we can only add things to our tree. To be able to
remove and modify the tree we need two more parts: reconciliation and
the commit phase.
Now we can go all the way from our JSX-like notation to a rendered
tree in the browser's DOM! But so far we can only add things to our
tree. To be able to remove and modify the tree we need one more part:
reconciliation.
** Reconciliation
A tale of two trees. These are the two trees that people most often
@ -455,11 +461,11 @@ function render(element, container) {
}
#+END_SRC
TODO note that we are adding parent and domElement properties.
Now that we have a way to see what we rendered last time we can go
ahead and update our render method with the heuristics.
TODO note that we are adding parent and domElement properties.
#+BEGIN_SRC javascript
function render_internal(element, container, prevElement) {
let domElement, children;

Loading…
Cancel
Save