|
|
|
@ -115,7 +115,7 @@ 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~
|
|
|
|
|
** ~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
|
|
|
|
@ -226,25 +226,75 @@ So now that we've worked through JSX we're ready to tackle
|
|
|
|
|
|
|
|
|
|
TODO JSX also does validation and escapes input to prevent XXS
|
|
|
|
|
|
|
|
|
|
*** ~createElement~
|
|
|
|
|
** ~createElement~
|
|
|
|
|
|
|
|
|
|
A tale of two trees.
|
|
|
|
|
React expects nodes defined as Javascript objects that look like this:
|
|
|
|
|
|
|
|
|
|
#+BEGIN_SRC javascript
|
|
|
|
|
{
|
|
|
|
|
type: NODE_TYPE,
|
|
|
|
|
props: {
|
|
|
|
|
propA: VALUE,
|
|
|
|
|
propB: VALUE,
|
|
|
|
|
...
|
|
|
|
|
children: STRING | ARRAY
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#+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
|
|
|
|
|
~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.
|
|
|
|
|
|
|
|
|
|
#+BEGIN_SRC javascript
|
|
|
|
|
function createElement(node) {
|
|
|
|
|
if (typeof node === 'string') {
|
|
|
|
|
// an array: not text, number, or other primitive
|
|
|
|
|
if (typeof node === 'object') {
|
|
|
|
|
const [ tag, props, children ] = node;
|
|
|
|
|
return {
|
|
|
|
|
type: 'TEXT_ELEMENT'
|
|
|
|
|
}
|
|
|
|
|
const [ tag, props, children ] = node;
|
|
|
|
|
const element = document.createDOMElement(tag);
|
|
|
|
|
for ([key, val] in props) {
|
|
|
|
|
element[key] = val;
|
|
|
|
|
type: tag,
|
|
|
|
|
props: {
|
|
|
|
|
...props,
|
|
|
|
|
children: children.map(createElement)
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
children.forEach(createElement);
|
|
|
|
|
|
|
|
|
|
// primitives like text or number
|
|
|
|
|
return {
|
|
|
|
|
type: 'TEXT',
|
|
|
|
|
props: {
|
|
|
|
|
nodeValue: node,
|
|
|
|
|
children: []
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
|
|
Our ~createElement~ has two main parts: complex elements and primitive
|
|
|
|
|
elements. The first part tests whether ~node~ is a complex node
|
|
|
|
|
(specified by an array) and then generates an ~element~ object based
|
|
|
|
|
on the input node. It recursively calls ~createElement~ to generate an
|
|
|
|
|
array of children elements. If the node is not complex then we
|
|
|
|
|
generate an element of type 'TEXT' which we use for all primitives
|
|
|
|
|
like strings and numbers.
|
|
|
|
|
|
|
|
|
|
That's it. Now we have everything we need to actually begin the
|
|
|
|
|
process of rendering our tree to the DOM!
|
|
|
|
|
|
|
|
|
|
*** Reconciliation
|
|
|
|
|
A tale of two trees.
|
|
|
|
|
* Rendering Model
|
|
|
|
|
React calls shouldComponentUpdate to know if it should re-render the
|
|
|
|
|
component. by default it returns true.
|
|
|
|
@ -267,6 +317,7 @@ function createElement(node) {
|
|
|
|
|
* Concurrent Rendering
|
|
|
|
|
* UX
|
|
|
|
|
* JS Service Workers
|
|
|
|
|
* Keys
|
|
|
|
|
* Reconciliation
|
|
|
|
|
- diffing algorithm based on heuristics. generic algorithm is O(n^3)
|
|
|
|
|
- "Fiber" algorithm notes
|
|
|
|
|