Kostiantyn Synyshyn
JS engineer
React performance optimisations
by Kostiantyn Synyshyn Front-end Developer at Levi Nine
Native events recap
Lazy evaluation
Actual React render process
What does React do to optimise performance?
What should we do (not do) to optimise performance of application?
<ul>
<li onclick="forLulz1()">It </li>
<li onclick="forLulz2()">is</li>
<li onclick="forLulz3()">useless</li>
</ul>
<ul onclick="forLulz()">
<li>Not</li>
<li>so</li>
<li>useless</li>
</ul>
Capturing
Bubbling
stopPropagation()
preventDefault()
element.addEventListener('eventGoesHere', callbackGoesHere, {capture : true | false})
// Example
submitButton.addEventListener('click', (event)=> console.log(event), true)
<html>
<body>
<div id="first">
<div id="second">
<div id="third">I am event target</div>
</div>
</div>
</body>
</html>
document.getElementById('third').addEventListener(
'click',
(e)=> {
console.log('third was clicked');
},
true,
);
propagation - is mechanism capturing, bubbling - are phases
const myClickEventHandler = (event) => {
event.stopPropagation()
alert('I will stop propagation,but do not know at which phase yet')
}
// will call all parents event listeners with {capture : true }, but won't let the event propagate any further
element.addEventListener('click',myClickEventHandler, true)
PS: according to w3c spec there is the third one - target phase
- just prevents default behaviour (action) for element.
- only compute value when needed
Lazy (pull model) | Eager (push model) |
---|---|
expressions are not evaluated when they are bound to variables, but their evaluation is deferredย until their results are needed by other computations | expressions are evaluated as declared |
Memory usage becomes unpredictable | Memory usage is predictable |
f :: Int -> Int -> Int ->
f x y = y
// f (1 + 2) 3 = 3 || (1+2) is never evaluated
const data = (1 + 2) + 3 // gets evaluated immediately
const handledNativeEvents = ['click', 'change', 'touch', 'scroll', 'dbclick', ...]
const reactEventHandlerPropByEventName = {
'click': 'onClick',
'dblclick': 'onDoubleClick',
...
}
const prioritiesByEventName = {
'click': 0, // DiscreteEvent
'drag': 1, // UserBlockingEvent
'load': 2, // ContinuousEvent
...
};
- react "knows" about native events obviously
react creates a map
- react prioritizes events by types
import { StrictMode } from "react";
import ReactDOM from "react-dom";
import App from "./App";
const rootElement = document.getElementById("root");
ReactDOM.render(
<StrictMode>
<App />
</StrictMode>,
rootElement
);
Event handlers registrations, are made during the creation of the root Fiber node, where React is initialized.
...
handledNativeEvents.forEach(eventName => {
rootDomNode.addEventListener(eventName, myEventListener);
rootDomNode.addEventListener(eventName, myEventListener, true);
}
...
Root - is the root cause of everything in React
React puts on DOM nodes a reference to the Fiber node under a dynamic key named [internalInstanceKey] and the props under the key [internalPropsKey].
everything is on Root, and all events are dispatchEvents.
view = React(data)
Render !== DOM updates
function Greetings(){
return [
<StyledHeader color="rebeccapurple">
Hello from functional component
</StyledHeader>
<div>
<span>I will be a text node soon ๐</span>
</div>
]
}
return [
React.createElement(
/* type */ StyledHeader,
/* props */ { color: 'rebeccapurple' },
/* children */ 'Hello from functional component'),
React.createElement(
'div',
null,
React.createElement(
'span',
null,
'I will be a text node soon ๐'))
]
=
{
type: StyledHeader,
props: {
color: 'rebeccapurple',
children: 'Hello from functional component',
},
key: null,
ref: null,
$$typeof: Symbol.for('react.element')
},
{
type: 'div',
props: {
children: {
{
type: 'span',
props: {
children: 'I will be a text node soon ๐'
},
key: null,
ref: null,
$$typeof: Symbol.for('react.element')
}
},
},
key: null,
ref: null,
$$typeof: Symbol.for('react.element')
}
Components tree you've written using JSX
Elements react created after calling render
Corresponding fiber nodes
We are callable( )
We are IMMUTABLE
We are mutable
Do same work faster
Do less work
Memoize it properly(useMemo)
Thank you!
Q&A
By Kostiantyn Synyshyn
React performance optimisations