Chapter 1 & 2 edits.

master
Thomas Hintz 4 years ago
parent 7f78c63348
commit 172f7b201f

@ -328,7 +328,8 @@ process of rendering our tree to the DOM!
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
nodes to actually displaying something on screen?
nodes to actually displaying something on screen? The next puzzle we
will be solving is the render method.
The signature for our ~render~ method should be familiar to you:
@ -336,8 +337,8 @@ The signature for our ~render~ method should be familiar to you:
function render(element, container)
#+END_SRC
Doing the initial render on a tree of elements is quite simple. In
psuedocode it looks like this:
This is the same signature as that of React itself. We begin by just
focusing on the initial render. In pseudocode it looks like this:
#+BEGIN_SRC javascript
function render(element, container) {
@ -349,10 +350,14 @@ function render(element, container) {
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.
container.
Now that we have an idea of what to build we will work on expanding
the pseudocode until we have our own fully functional ~render~ method
using the same general algorithm React uses. In our first pass we will
focus on the initial render and ignore reconciliation.
TODO note what reconciliation is
#+BEGIN_SRC javascript
function render(element, container) {
@ -366,9 +371,7 @@ function render(element, container) {
// set its properties
Object.keys(props)
.filter((key) => key !== 'children')
.forEach((key) => {
domElement[key] = props[key];
});
.forEach((key) => domElement[key] = props[key]);
// render its children
props.children.forEach((child) => render(child, domElement));
@ -378,12 +381,13 @@ function render(element, container) {
}
#+END_SRC
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).
The ~render~ method starts 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 the keys, setting
each property directly. Following that, we render each of the children
by looping over the children and recursively calling ~render~ on each
child with the ~container~ set to the current DOM element (which is
each child's parent).
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
@ -392,15 +396,15 @@ reconciliation.
** Reconciliation
A tale of two trees. These are the two trees that people most often
talk about when talking about React's "secret sauce": the VDOM or
virtual DOM and the current render tree. This idea is what originally
set React apart. React's reconciliation is what allows you to program
talk about when talking about React's "secret sauce": the virtual DOM
and the browser's DOM tree. This idea is what originally set React
apart. React's reconciliation is what allows you to program
declaratively. Reconciliation is what makes it so we no longer have to
manually update and modify the DOM whenever our own internal state
changes and in a lot of ways is that makes React, React.
changes. In a lot of ways, it is what makes React, React.
Conceptually the way this works is that React generates a new element
tree for every render and compares to the newly generated tree to the
Conceptually, the way this works is that React generates a new element
tree for every render and compares the newly generated tree to the
tree generated on the previous render. Where it finds differences in
the tree it knows to mutate the DOM state. This is the "tree diffing"
algorithm.
@ -408,27 +412,27 @@ algorithm.
Unfortunately those researching tree diffing in Computer Science have
not yet produced a generic algorithm with sufficient performance for
use in something like React as the current best still [[https://grfia.dlsi.ua.es/ml/algorithms/references/editsurvey_bille.pdf][runs in
O(n^3)]]. This leads to the largest performance related aspect in all of
React.
Since an O(n^3) algorithm isn't going to cut it the creators of React
instead use a set of heuristics to determine what parts of the tree
have changed. Understanding how the React tree diffing algorithm works
in general and the heuristics currently in use can help immensely in
detecting and fixing React performance bottlenecks. And beyond that it
can help one's understanding of some of React's quirks and usage. Even
though this algorithm is internal to React and can be changed anytime
its details have leaked out in some ways and are overall unlikely to
change in major ways without larger changes to React.
According to the React documentation their diffing algorithm is O(n)
O(n^3)]].
Since an O(n^3) algorithm isn't going to cut it in the real-world, the
creators of React instead use a set of heuristics to determine what
parts of the tree have changed. Understanding how the React tree
diffing algorithm works in general and the heuristics currently in use
can help immensely in detecting and fixing React performance
bottlenecks. And beyond that it can help one's understanding of some
of React's quirks and usage. Even though this algorithm is internal to
React and can be changed anytime its details have leaked out in some
ways and are overall unlikely to change in major ways without larger
changes to React itself.
According to the [[https://reactjs.org/docs/reconciliation.html][React documentation]] their diffing algorithm is O(n)
and based on two major components:
- Elements of differing types will yield different trees
- You can hint at tree changes with the ~key~ prop.
In this section we will focus on the first part: differing
types. Later on we will discuss and implement the ~key~ prop.
In this section we will focus on the first part: differing types. In a
later chapter we will discuss and implement the ~key~ prop.
The approach we will take here is to integrate the heuristics that
React uses into our render method. This is similar to how React itself
@ -438,10 +442,9 @@ talk about Fibers.
Before we get into the code changes that implement the heuristics it
is important to remember that React /only/ looks at an element's type,
existence, and key. It does not do any other diffing. It does not diff
props. It does not diff sub-trees of modified parents. If you could
only take away one thing from this book it would that.
props. It does not diff sub-trees of modified parents.
Here is a more in depth look at the algorithm we will be implementing:
Here is an overview of the algorithm we will be implementing:
#+BEGIN_SRC javascript
if (!element && prevElement)
@ -456,11 +459,11 @@ Here is a more in depth look at the algorithm we will be implementing:
Notice that in every case, except deletion, we still call ~render~ on
the element's children. While its possible that the children will be
able to reuse their associated DOM elements, ~render~ will still be
run on them.
able to reuse their associated DOM elements, their ~render~ methods
will still be invoked.
Now, to get started with our render method we must make some
modifications to our previous render methods. First, we need to be
modifications to our previous render method. First, we need to be
able to store and retrieve the previous render tree. Then we need to
add code to compare parts of the tree to decide if we need to
re-render something or if we can re-use DOM elements from the previous
@ -485,11 +488,15 @@ function render(element, container) {
}
#+END_SRC
As you can see, the change we made is to move the core of our
algorithm into a new function called ~render_internal~ and pass in the
result of our last render to ~render_internal~.
Now that we have stored our last render tree we can go ahead and
update our render method with the heuristics for reusing the DOM
elements. We name it ~render_internal~ because it is what controls the
rendering but takes an additional argument now: the
~prevElement~. ~preElement~ is a reference to the corresponding
~prevElement~. ~prevElement~ is a reference to the corresponding
~element~ from the previous render and contains a reference to its
associated DOM element and parent DOM element. If it's the first
render or if we are rendering a new node or branch to the tree than
@ -530,24 +537,26 @@ function render_internal(element, container, prevElement) {
}
#+END_SRC
The only time we can't set DOM properties on our element and render
its children is when we are deleting an existing DOM element. We use
this observation to group the calls for ~setDOMProps~ and
~renderChildren~. Choosing when to append a new DOM element to the
The only time we shouldn't set DOM properties on our element and
render its children is when we are deleting an existing DOM
element. We use this observation to group the calls for ~setDOMProps~
and ~renderChildren~. Choosing when to append a new DOM element to the
container is also part of the heuristics. If we can reuse an existing
DOM element then we do but if the element type has changed or if there
was no corresponding existing DOM element then and only then do we
append a new DOM element. This ensures the actual DOM tree isn't being
swapped out every time we render, only the elements that change
are. When a new DOM element is appended to the tree React would invoke
~componentDidMount~.
replaced every time we render, only the elements that change are
replaced.
In React, when a new DOM element is appended to the DOM tree, React
would invoke ~componentDidMount~ or ~useEffect~.
Next up we'll go through all the auxiliary methods that complete the
implementation.
Removing a DOM element is straightforward; we just ~removeChild~ on
the parent element. In React, before removing the element, it invoke
~componentWillUnmount~.
the parent element. Before removing the element, React would invoke
~componentWillUnmount~ and ~useEffect~.
#+BEGIN_SRC javascript
function removeDOMElement(prevElement) {
@ -570,7 +579,7 @@ function createDOMElement(element) {
}
#+END_SRC
To set the props on an element we first clear all the existing props
To set the props on an element, we first clear all the existing props
and then loop through the current props, setting them accordingly. Of
course we filter out the ~children~ prop since we use that elsewhere
and it isn't intended to be set directly.
@ -594,7 +603,7 @@ function setDOMProps(element, domElement, prevElement) {
#+begin_note
React is more intelligent about only updating or removing props that
need to be.
need to be updated or removed.
#+end_note
#+begin_warning
@ -606,11 +615,11 @@ important though.
For rendering children we use two loops. The first loop removes any
elements that are no longer being used. This would happen when the
number of children is decreased. The second loop starts at the first
child and then iterates through all of the current children calling
~render_internal~ on each child. When ~render_internal~ is called the
corresponding previous element in that position is passed to
~render_internal~ or ~undefined~ if there is no corresponding element,
like when the list of children has grown.
child and then iterates through all of the children of the parent
element, calling ~render_internal~ on each child. When
~render_internal~ is called the corresponding previous element in that
position is passed to ~render_internal~, or ~undefined~ if there is no
corresponding element, like when the list of children has grown.
#+BEGIN_SRC javascript
function renderChildren(element, domElement, prevElement = { props: { children: [] }}) {
@ -642,12 +651,12 @@ uses when rendering lists of children.
There are a few things to note here. First it is important to pay
attention to when React will be removing a DOM element from the tree
and adding a new one as this is when the related lifecycle events are
invoked. And invoking those lifecycle methods, and the whole process
of tearing down and building up a component is expensive. So again you
can see how a bad key would lead to another performance bottleneck
since React will be doing this on all or many of the elements in a
list frequently.
and adding a new one as this is when the related lifecycle events or
hooks are invoked. And invoking those lifecycle methods or hooks, and
the whole process of tearing down and building up a component is
expensive. So again, you can see how a bad key would lead to another
performance bottleneck since React will be doing this on all or many
of the elements in a list frequently.
** Fibers
@ -674,11 +683,18 @@ this more.
** Conclusion
At this point you should have enough information to begin to diagnose
performance issues and prevent them from occurring in the first
place. In the rest of the book we are going to be refining this model
and looking at practical applications of it so that we are prepared to
build high performance React applications and diagnose any bottlenecks.
Of course our version of React elides over many details that React
must contend with like props, state, lifecycle methods, and hooks. For
understanding how to build high-performance React applications,
however, the most important piece to understand is how and when React
renders components, which is what we have learned in creating our own
mini version of React.
At this point you should have an understanding of how React works. In
the rest of the book we are going to be refining this model and
looking at practical applications of it so that we are prepared to
build high performance React applications and diagnose any
bottlenecks.
TODO maybe a graphic summarizing the heuristics?
@ -753,6 +769,8 @@ React API itself, then we will extend our React implementation from
chapter one to support the same API. Then we will discuss its usage
and analyze when and how to use it.
TODO useCallback
* Diagnosing Bottlenecks
:PROPERTIES:
:EXPORT_FILE_NAME: manuscript/diagnosing-bottlenecks.markua

@ -144,7 +144,7 @@ That's it. Now we have everything we need to actually begin the process of rende
## 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 nodes to actually displaying something on screen?
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 nodes to actually displaying something on screen? The next puzzle we will be solving is the render method.
The signature for our `render` method should be familiar to you:
@ -153,7 +153,7 @@ The signature for our `render` method should be familiar to you:
function render(element, container)
```
Doing the initial render on a tree of elements is quite simple. In psuedocode it looks like this:
This is the same signature as that of React itself. We begin by just focusing on the initial render. In pseudocode it looks like this:
{format: "javascript"}
```
@ -164,7 +164,11 @@ function render(element, container) {
container.appendChild(domElement);
```
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.
Our DOM element is created first. Then we set the properties, render children elements, and finally append the whole tree to the container.
Now that we have an idea of what to build we will work on expanding the pseudocode until we have our own fully functional `render` method using the same general algorithm React uses. In our first pass we will focus on the initial render and ignore reconciliation.
TODO note what reconciliation is
{format: "javascript"}
```
@ -179,9 +183,7 @@ function render(element, container) {
// set its properties
Object.keys(props)
.filter((key) => key !== 'children')
.forEach((key) => {
domElement[key] = props[key];
});
.forEach((key) => domElement[key] = props[key]);
// render its children
props.children.forEach((child) => render(child, domElement));
@ -191,32 +193,32 @@ function render(element, container) {
}
```
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).
The `render` method starts 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 the keys, setting each property directly. Following that, we render each of the children by looping over the children and recursively calling `render` on each child with the `container` set to the current DOM element (which is each child's parent).
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 talk about when talking about React's "secret sauce": the VDOM or virtual DOM and the current render tree. This idea is what originally set React apart. React's reconciliation is what allows you to program declaratively. Reconciliation is what makes it so we no longer have to manually update and modify the DOM whenever our own internal state changes and in a lot of ways is that makes React, React.
A tale of two trees. These are the two trees that people most often talk about when talking about React's "secret sauce": the virtual DOM and the browser's DOM tree. This idea is what originally set React apart. React's reconciliation is what allows you to program declaratively. Reconciliation is what makes it so we no longer have to manually update and modify the DOM whenever our own internal state changes. In a lot of ways, it is what makes React, React.
Conceptually the way this works is that React generates a new element tree for every render and compares to the newly generated tree to the tree generated on the previous render. Where it finds differences in the tree it knows to mutate the DOM state. This is the "tree diffing" algorithm.
Conceptually, the way this works is that React generates a new element tree for every render and compares the newly generated tree to the tree generated on the previous render. Where it finds differences in the tree it knows to mutate the DOM state. This is the "tree diffing" algorithm.
Unfortunately those researching tree diffing in Computer Science have not yet produced a generic algorithm with sufficient performance for use in something like React as the current best still [runs in O(n^3^)](https://grfia.dlsi.ua.es/ml/algorithms/references/editsurvey_bille.pdf). This leads to the largest performance related aspect in all of React.
Unfortunately those researching tree diffing in Computer Science have not yet produced a generic algorithm with sufficient performance for use in something like React as the current best still [runs in O(n^3^)](https://grfia.dlsi.ua.es/ml/algorithms/references/editsurvey_bille.pdf).
Since an O(n^3^) algorithm isn't going to cut it the creators of React instead use a set of heuristics to determine what parts of the tree have changed. Understanding how the React tree diffing algorithm works in general and the heuristics currently in use can help immensely in detecting and fixing React performance bottlenecks. And beyond that it can help one's understanding of some of React's quirks and usage. Even though this algorithm is internal to React and can be changed anytime its details have leaked out in some ways and are overall unlikely to change in major ways without larger changes to React.
Since an O(n^3^) algorithm isn't going to cut it in the real-world, the creators of React instead use a set of heuristics to determine what parts of the tree have changed. Understanding how the React tree diffing algorithm works in general and the heuristics currently in use can help immensely in detecting and fixing React performance bottlenecks. And beyond that it can help one's understanding of some of React's quirks and usage. Even though this algorithm is internal to React and can be changed anytime its details have leaked out in some ways and are overall unlikely to change in major ways without larger changes to React itself.
According to the React documentation their diffing algorithm is O(n) and based on two major components:
According to the [React documentation](https://reactjs.org/docs/reconciliation.html) their diffing algorithm is O(n) and based on two major components:
* Elements of differing types will yield different trees
* You can hint at tree changes with the `key` prop.
In this section we will focus on the first part: differing types. Later on we will discuss and implement the `key` prop.
In this section we will focus on the first part: differing types. In a later chapter we will discuss and implement the `key` prop.
The approach we will take here is to integrate the heuristics that React uses into our render method. This is similar to how React itself does it and we will discuss React's actual implementation later when we talk about Fibers.
Before we get into the code changes that implement the heuristics it is important to remember that React *only* looks at an element's type, existence, and key. It does not do any other diffing. It does not diff props. It does not diff sub-trees of modified parents. If you could only take away one thing from this book it would that.
Before we get into the code changes that implement the heuristics it is important to remember that React *only* looks at an element's type, existence, and key. It does not do any other diffing. It does not diff props. It does not diff sub-trees of modified parents.
Here is a more in depth look at the algorithm we will be implementing:
Here is an overview of the algorithm we will be implementing:
{format: "javascript"}
```
@ -230,9 +232,9 @@ else if (element.type !== prevElement.type)
// replace dom element, render children
```
Notice that in every case, except deletion, we still call `render` on the element's children. While its possible that the children will be able to reuse their associated DOM elements, `render` will still be run on them.
Notice that in every case, except deletion, we still call `render` on the element's children. While its possible that the children will be able to reuse their associated DOM elements, their `render` methods will still be invoked.
Now, to get started with our render method we must make some modifications to our previous render methods. First, we need to be able to store and retrieve the previous render tree. Then we need to add code to compare parts of the tree to decide if we need to re-render something or if we can re-use DOM elements from the previous render tree. And last we need to return a tree of elements that can be used in the next render as a comparison and to reference the DOM elements that we create. These new elements will have the same structure as our current elements but we will add two new properties: `domElement` and `parent`. `domElement` is the DOM element associated with our synthetic element and `parent` is a reference to the parent DOM element.
Now, to get started with our render method we must make some modifications to our previous render method. First, we need to be able to store and retrieve the previous render tree. Then we need to add code to compare parts of the tree to decide if we need to re-render something or if we can re-use DOM elements from the previous render tree. And last we need to return a tree of elements that can be used in the next render as a comparison and to reference the DOM elements that we create. These new elements will have the same structure as our current elements but we will add two new properties: `domElement` and `parent`. `domElement` is the DOM element associated with our synthetic element and `parent` is a reference to the parent DOM element.
Here we begin by adding a global object that will store our last render tree, keyed by the `container`.
@ -247,7 +249,9 @@ function render(element, container) {
}
```
Now that we have stored our last render tree we can go ahead and update our render method with the heuristics for reusing the DOM elements. We name it `render_internal` because it is what controls the rendering but takes an additional argument now: the `prevElement`. `preElement` is a reference to the corresponding `element` from the previous render and contains a reference to its associated DOM element and parent DOM element. If it's the first render or if we are rendering a new node or branch to the tree than `prevElement` will be `undefined`. If, however, `element` is `undefined` and `prevElement` is defined then we know we need to delete a node that previously existed.
As you can see, the change we made is to move the core of our algorithm into a new function called `render_internal` and pass in the result of our last render to `render_internal`.
Now that we have stored our last render tree we can go ahead and update our render method with the heuristics for reusing the DOM elements. We name it `render_internal` because it is what controls the rendering but takes an additional argument now: the `prevElement`. `prevElement` is a reference to the corresponding `element` from the previous render and contains a reference to its associated DOM element and parent DOM element. If it's the first render or if we are rendering a new node or branch to the tree than `prevElement` will be `undefined`. If, however, `element` is `undefined` and `prevElement` is defined then we know we need to delete a node that previously existed.
{format: "javascript"}
```
@ -283,11 +287,13 @@ function render_internal(element, container, prevElement) {
}
```
The only time we can't set DOM properties on our element and render its children is when we are deleting an existing DOM element. We use this observation to group the calls for `setDOMProps` and `renderChildren`. Choosing when to append a new DOM element to the container is also part of the heuristics. If we can reuse an existing DOM element then we do but if the element type has changed or if there was no corresponding existing DOM element then and only then do we append a new DOM element. This ensures the actual DOM tree isn't being swapped out every time we render, only the elements that change are. When a new DOM element is appended to the tree React would invoke `componentDidMount`.
The only time we shouldn't set DOM properties on our element and render its children is when we are deleting an existing DOM element. We use this observation to group the calls for `setDOMProps` and `renderChildren`. Choosing when to append a new DOM element to the container is also part of the heuristics. If we can reuse an existing DOM element then we do but if the element type has changed or if there was no corresponding existing DOM element then and only then do we append a new DOM element. This ensures the actual DOM tree isn't being replaced every time we render, only the elements that change are replaced.
In React, when a new DOM element is appended to the DOM tree, React would invoke `componentDidMount` or `useEffect`.
Next up we'll go through all the auxiliary methods that complete the implementation.
Removing a DOM element is straightforward; we just `removeChild` on the parent element. In React, before removing the element, it invoke `componentWillUnmount`.
Removing a DOM element is straightforward; we just `removeChild` on the parent element. Before removing the element, React would invoke `componentWillUnmount` and `useEffect`.
{format: "javascript"}
```
@ -307,7 +313,7 @@ function createDOMElement(element) {
}
```
To set the props on an element we first clear all the existing props and then loop through the current props, setting them accordingly. Of course we filter out the `children` prop since we use that elsewhere and it isn't intended to be set directly.
To set the props on an element, we first clear all the existing props and then loop through the current props, setting them accordingly. Of course we filter out the `children` prop since we use that elsewhere and it isn't intended to be set directly.
{format: "javascript"}
```
@ -327,11 +333,11 @@ function setDOMProps(element, domElement, prevElement) {
}
```
I> React is more intelligent about only updating or removing props that need to be.
I> React is more intelligent about only updating or removing props that need to be updated or removed.
W> This algorithm for setting props does not correctly handle events which must be treated specially. For this exercise that detail is not important though.
For rendering children we use two loops. The first loop removes any elements that are no longer being used. This would happen when the number of children is decreased. The second loop starts at the first child and then iterates through all of the current children calling `render_internal` on each child. When `render_internal` is called the corresponding previous element in that position is passed to `render_internal` or `undefined` if there is no corresponding element, like when the list of children has grown.
For rendering children we use two loops. The first loop removes any elements that are no longer being used. This would happen when the number of children is decreased. The second loop starts at the first child and then iterates through all of the children of the parent element, calling `render_internal` on each child. When `render_internal` is called the corresponding previous element in that position is passed to `render_internal`, or `undefined` if there is no corresponding element, like when the list of children has grown.
{format: "javascript"}
```
@ -352,7 +358,7 @@ function renderChildren(element, domElement, prevElement = { props: { children:
It's very important to understand the algorithm used here because this is essentially what happens in React when incorrect keys are used, like a list index. And this is why keys are so critical to high performance (and correct) React code. For example, in our algorithm here, if you removed an item from the front of the list you may cause every element in the list to be created anew in the DOM if the types no longer match up. Later on, in the chapter on keys, we will update this algorithm to incorporate keys. It's actually only a minor difference in determining which `child` gets paired with which `prevChild`. Otherwise this is effectively the same algorithm React uses when rendering lists of children.
There are a few things to note here. First it is important to pay attention to when React will be removing a DOM element from the tree and adding a new one as this is when the related lifecycle events are invoked. And invoking those lifecycle methods, and the whole process of tearing down and building up a component is expensive. So again you can see how a bad key would lead to another performance bottleneck since React will be doing this on all or many of the elements in a list frequently.
There are a few things to note here. First it is important to pay attention to when React will be removing a DOM element from the tree and adding a new one as this is when the related lifecycle events or hooks are invoked. And invoking those lifecycle methods or hooks, and the whole process of tearing down and building up a component is expensive. So again, you can see how a bad key would lead to another performance bottleneck since React will be doing this on all or many of the elements in a list frequently.
## Fibers
@ -362,7 +368,9 @@ But even with such a large change, the underlying algorithms for deciding how an
## Conclusion
At this point you should have enough information to begin to diagnose performance issues and prevent them from occurring in the first place. In the rest of the book we are going to be refining this model and looking at practical applications of it so that we are prepared to build high performance React applications and diagnose any bottlenecks.
Of course our version of React elides over many details that React must contend with like props, state, lifecycle methods, and hooks. For understanding how to build high-performance React applications, however, the most important piece to understand is how and when React renders components, which is what we have learned in creating our own mini version of React.
At this point you should have an understanding of how React works. In the rest of the book we are going to be refining this model and looking at practical applications of it so that we are prepared to build high performance React applications and diagnose any bottlenecks.
TODO maybe a graphic summarizing the heuristics?

@ -28,4 +28,6 @@ This is indeed such a common bottleneck and solution that React provides an API
We will learn about this API by first looking at the signatures of the React API itself, then we will extend our React implementation from chapter one to support the same API. Then we will discuss its usage and analyze when and how to use it.
TODO useCallback

Loading…
Cancel
Save