Adding createElement.
This commit is contained in:
@@ -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
|
||||
function createElement(node) {
|
||||
if (typeof node === 'string') {
|
||||
return {
|
||||
type: 'TEXT_ELEMENT'
|
||||
{
|
||||
type: NODE_TYPE,
|
||||
props: {
|
||||
propA: VALUE,
|
||||
propB: VALUE,
|
||||
...
|
||||
children: STRING | ARRAY
|
||||
}
|
||||
const [ tag, props, children ] = node;
|
||||
const element = document.createDOMElement(tag);
|
||||
for ([key, val] in props) {
|
||||
element[key] = val;
|
||||
}
|
||||
children.forEach(createElement);
|
||||
}
|
||||
#+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) {
|
||||
// an array: not text, number, or other primitive
|
||||
if (typeof node === 'object') {
|
||||
const [ tag, props, children ] = node;
|
||||
return {
|
||||
type: tag,
|
||||
props: {
|
||||
...props,
|
||||
children: children.map(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
|
||||
|
||||
Reference in New Issue
Block a user