react - render() to dom - boris dinkevich - codemotion milan 2016

131
render() to DOM Boris Dinkevich MILAN 25-26 NOVEMBER 2016

Upload: codemotion

Post on 12-Apr-2017

161 views

Category:

Technology


0 download

TRANSCRIPT

render() to DOMBoris Dinkevich

MILAN 25-26 NOVEMBER 2016

from

render() to

DOM

Boris Dinkevich [email protected]

COMPLICATEDBAD ARCHITECTURE OPTIMISATIONS

Boris Dinkevich

- React evangelist - Cat aficionado - Co-Author of “The Redux book” - Organiser AngularUP & ReactNext

Co-Founder @ 500Tech

A WORD ON TREES

Our code today

const Todos = () => ( <ul> <li>Todo</li> </ul>);

De-JSX

const Todos = () => ( <ul> <li>Stuff</li> </ul>);

const Todos = () => ( React.createElement("ul", null, React.createElement("li", null, "Stuff" ), ); );

Chrome dev tools?

WHY REACT?

DOM is slowLets minimise writes…

Our Sample App

TodosHeader

TodoTodo

App

Tree & DOM

TodosHeader

“div”

“Welcome”

“h1”

“div”

Todo

“Two”

“li”

“ul”

Todo

“One”

“li”

“div”

“Welcome”

“h1”

“div”

“Two”

“li”

“ul”

“One”

“li”

Our tree Our DOM

App

Tree & DOM

TodosHeader

“div”

“Welcome”

“h1”

“div”

Todo

“Two”

“li”

“ul”

Todo

“One”

“li”

Old New

App

TodosHeader

“div”

“Welcome”

“h1”

“div”

Todo

“Two”

“li”

“ul”

Todo

“Million”

“li”

App

Tree & DOM

TodosHeader

“div”

“Welcome”

“h1”

“div”

Todo

“Two”

“li”

“ul”

Todo

“Million”

“li”

“div”

“Welcome”

“h1”

“div”

“Two”

“li”

“ul”

“One”

“li”

Our tree Our DOM

App

Tree & DOM

TodosHeader

“div”

“Welcome”

“h1”

“div”

Todo

“Two”

“li”

“ul”

Todo

“Million”

“li”

“div”

“Welcome”

“h1”

“div”

“Two”

“li”

“ul”

“Million”

“li”

Our tree Our DOM

App

Introducing BorisJS!1.Call render() to build tree - ”Future Tree”

2.Compare each element to DOM

3.Change when needed

4.Win!

React docs: “reads are slow”Lets open PR

Simple diff

function updateNode(node, value) { if (node.innerText !== value) { node.innerText = value; } }

60fpsTime per frame: 16.6ms

Time for 1000 read / write cycles: 36.15ms

Read & Write

Read then Write

Introducing BorisJS 2.01.Call render() to build tree

2.Read DOM into temp tree - “Current Tree" 3.Compare each element to temp tree

4.Change when needed

5.Win!

“temp tree”… sounds familiar

Pre cache1. Call render() to build “Future Tree”

2. Compare each element to “Current Tree“

3. Change DOM when needed

4.Save “Future Tree” as “Current Tree” 5. Win!

What about first “Current Tree”?

Introducing BorisJS 3.0Initial Render

1.Call render() to build tree

2.Save as “Current Tree” 3.Create initial DOM

Updates

1.Call render() to build “Future Tree”

2.Compare each element to “Current Tree” 4.Change DOM when needed

5.Save “Future Tree” as “Current Tree”

6.Win!

NO READS?

Todos.setState({ todos: [’XXXXX’, ‘Two’] });

Todos• One • Two

Todos• XXXXX • Two

todos = document.getElementById('app').children[0].children[1]; todos.removeChild(todos.childNodes[0]);

Todos.setState({ todos: [‘XXXXX’, ‘Dos’] });

Todos• Dos

Todos• One • Two

Todos• Two

I LiedGet <input /> values?

In React• Initial Render

• Updates

FIRST RUN

React.createElement(App);

Starting

function Todos()

function Header()

“div”

“Welcome”

“h1”

“div”

function Todo()

“Two”

“li”

“ul

function Todo()

“One”

“li”

function App()

Mounting markup

function Todos()

function Header()

“div”

“Welcome”

“h1”

“div”

function Todo()

“Two”

“li”

“ul

function Todo()

“One”

“li”

function App()

Mounting markup

function Todos()

function Header()

“div”

“Welcome”

“h1”

“div”

function Todo()

“Two”

“li”

“ul

function Todo()

“One”

“li”

function App()

“Welcome”

“h1”

“div”

Mounting markup

function Todos()

function Header()

“div”

“Welcome”

“h1”

“div”

function Todo()

“Two”

“li”

“ul

function Todo()

“One”

“li”

function App()

“Welcome”

“h1”

“div”

Mounting markup

function Todos()

function Header()

“div”

“Welcome”

“h1”

“div”

function Todo()

“Two”

“li”

“ul

function Todo()

“One”

“li”

function App()

“Welcome”

“h1”

“div”

“One”

“li”

Mounting markup

function Todos()

function Header()

“div”

“Welcome”

“h1”

“div”

function Todo()

“Two”

“li”

“ul

function Todo()

“One”

“li”

function App()

“Welcome”

“h1”

“div”

“One”

“li”

Mounting markup

function Todos()

function Header()

“div”

“Welcome”

“h1”

“div”

function Todo()

“Two”

“li”

“ul

function Todo()

“One”

“li”

function App()

“Welcome”

“h1”

“div”

“Two”

“li”

“One”

“li”

Mounting markup

function Todos()

function Header()

“div”

“Welcome”

“h1”

“div”

function Todo()

“Two”

“li”

“ul

function Todo()

“One”

“li”

function App()

“Welcome”

“h1”

“div”

“Two”

“li”

“ul”

“One”

“li”

Mounting markup

function Todos()

function Header()

“div”

“Welcome”

“h1”

“div”

function Todo()

“Two”

“li”

“ul

function Todo()

“One”

“li”

function App()

“Welcome”

“h1”

“div”

“Two”

“li”

“ul”

“One”

“li”

Mounting markup

“div”

“div”

“Welcome”

“h1”

“div”

“Two”

“li”

“ul”

“One”

“li”

#app

markup

<body> <div id="app"></div></body>

render( React.createElement(App), document.getElementById('app') );

DOM IS READY!Or is it?

DOM and React

Event Handers

<Component onClick={} />

Connection

React

onClick

DOM

React DOM

Our Code

Different renderersDOM - onClick

Native - onPress

What does this mean?

<Header onClick={} />

<Header onPress={} />

What is “React”?

addons 1,334 isomorphic 3,428 shared 7,058

renderers/ art 641 dom 12,337 native 2,735 noop 192 shared 9,368

* lines of code in 15-stable

TREE UPDATE

What will cause React to render again?• setState()

• forceUpdate()

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Two”

“li”

“ul”

“One”

“li”

“div”

“Two”

“li”

“ul”

“One”

“li”

DOMReact Tree prev Virtual DOM

Todos.setState({ todos: ['Uno', 'Dos'] });

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Two”

“li”

“ul”

“One”

“li”

“div”

“Two”

“li”

“ul”

“One”

“li”

DOMReact Tree prev Virtual DOM

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Two”

“li”

“ul”

“One”

“li”

“div”

“Two”

“li”

“ul”

“One”

“li”

DOMReact Tree prev Virtual DOM

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Two”

“li”

“ul”

“One”

“li”

“div”

“Two”

“li”

“ul”

“One”

“li”

DOMReact Tree prev Virtual DOM

‘UNO’ ‘DOS’

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Two”

“li”

“ul”

“One”

“li”

“div”

“Two”

“li”

“ul”

“One”

“li”

DOMReact Tree prev Virtual DOM

‘UNO’ ‘DOS’

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Two”

“li”

“ul”

“One”

“li”

“div”

“Two”

“li”

“ul”

“One”

“li”

DOMReact Tree prev Virtual DOM

‘UNO’ ‘DOS’

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Two”

“li”

“ul”

“One”

“li”

“div”

“Two”

“li”

“ul”

“Uno”

“li”

DOMReact Tree prev Virtual DOM

‘UNO’ ‘DOS’

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Two”

“li”

“ul”

“Uno”

“li”

“div”

“Two”

“li”

“ul”

“Uno”

“li”

DOMReact Tree prev Virtual DOM

‘UNO’ ‘DOS’

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Two”

“li”

“ul”

“Uno”

“li”

“div”

“Two”

“li”

“ul”

“Uno”

“li”

DOMReact Tree prev Virtual DOM

‘UNO’ ‘DOS’

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Two”

“li”

“ul”

“Uno”

“li”

“div”

“Two”

“li”

“ul”

“Uno”

“li”

DOMReact Tree prev Virtual DOM

‘UNO’ ‘DOS’

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Two”

“li”

“ul”

“Uno”

“li”

“div”

“Two”

“li”

“ul”

“Uno”

“li”

DOMReact Tree prev Virtual DOM

‘UNO’ ‘DOS’

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Two”

“li”

“ul”

“Uno”

“li”

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

DOMReact Tree prev Virtual DOM

‘UNO’ ‘DOS’

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

DOMReact Tree prev Virtual DOM

‘UNO’ ‘DOS’

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

DOMReact Tree prev Virtual DOM

‘UNO’ ‘DOS’

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

DOMReact Tree prev Virtual DOM

‘UNO’ ‘DOS’

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

DOMReact Tree prev Virtual DOM

‘UNO’ ‘DOS’

Flow1. setState({ todos: [‘Uno’, ‘Dos’] });

2. Todos updated and rendering starts

3. Todo1 needs update

4. DOM updated

5. Todo2 needs update

6. DOM updated

AGAIN?

Todos.setState({ todos: ['Uno', 'Dos'] });

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

DOMReact Tree prev Virtual DOM

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

DOMReact Tree prev Virtual DOM

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

DOMReact Tree prev Virtual DOM

‘UNO’ ‘DOS’

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

DOMReact Tree prev Virtual DOM

‘UNO’ ‘DOS’

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

DOMReact Tree prev Virtual DOM

‘UNO’ ‘DOS’

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

“div”

“Dos”

“li”

“ul”

“Uno”

“li”

DOMReact Tree prev Virtual DOM

‘UNO’ ‘DOS’

LIFE CYCLE

function Todos()

“div”

function Todo()

{ title }

“li”

“ul”

function Todo()

{ title }

“li”

function App()

React Tree

componentWillMount componentDidMount componentWillUpdate componentDidUpdate componentWillUnmount …

MULTIPLE UPDATES

Multiple setState calls

Todos.setState({ todos: [‘Uno’, ‘Dos’] }); App.setState({ title: ‘Bye’ }); Todos.setState({ todos: [‘Raz’, ‘Dva’] });

How many render() ?

App()

Todos()

Todos()

Todos()

Todo()

App()

How many render() ?

App()

Todos()

Todos()

Todos()

Todo()

App()

How many render() ?

App()

Todos()

Todos()

Todos()

Todo()

App()

How many render() ?

App()

Todos()

Todos()

Todos()

Todo()

App() 0

1

1

How many render() ?

App()

Todos()

Todos()

Todos()

Todo()

App() 0

1

1

How many render() ?

App()

Todos()

Todos()

Todos()

Todo()

App() 1

1

1

How many render() ?

App()

Todos()

Todos()

Todos()

Todo()

App() 1

2

1

How many render() ?

App()

Todos()

Todos()

Todos()

Todo()

App() 1

2

2

How many render() ?

App()

Todos()

Todos()

Todos()

Todo()

App() 1

2

2

How many render() ?

App()

Todos()

Todos()

Todos()

Todo()

App() 1

3

2

How many render() ?

App()

Todos()

Todos()

Todos()

Todo()

App() 1

3

3

How many render() ?

App()

Todos()

Todos()

Todos()

Todo()

App() 1

3

3

transactions

How do we group?

Todos.setState({ todos: [‘Uno’, ‘Dos’] }); App.setState({ title: ‘Bye’ }); Todos.setState({ todos: [‘Raz’, ‘Dva’] });

Callback

Before

After

Transaction

Callback

Before

After

• Prepare

• Calculate final state • Update DOM • Run Callbacks

Transaction

• multiple setState() • Build list of changes

Todos

dirtyComponents

Todos.setState({ todos: [‘Uno’, ‘Dos’] });

{ todos: [‘Uno’, ‘Dos’] }

App

dirtyComponents

Todos.setState({ todos: [‘Uno’, ‘Dos’] }); App.setState({ title: ‘Bye’ });

{ todos: [‘Uno’, ‘Dos’] }

Todos

{ title: ‘Bye’ }

dirtyComponents

Todos.setState({ todos: [‘Uno’, ‘Dos’] }); App.setState({ title: ‘Bye’ }); Todos.setState({ todos: [‘Raz’, ‘Dva’] });

{ todos: [‘Uno’, ‘Dos’] } { todos: [‘Raz’, ‘Dva’] }

Todos

{ title: ‘Bye’ }

App

Finalize Transaction

How many render() ?

App()

Todos()

Todos()

Todo()

App() 0

0

0

How many render() ?

App()

Todos()

Todos()

Todo()

App() 0

0

0

How many render() ?

App()

Todos()

Todos()

Todo()

App() 0

0

0

Update the state to it’s latest version

How many render() ?

App()

Todos()

Todos()

Todo()

App() 0

1

0

How many render() ?

App()

Todos()

Todos()

Todo()

App() 0

1

1

How many render() ?

App()

Todos()

Todos()

Todo()

App() 0

1

1

How many render() ?

App()

Todos()

Todos()

Todo()

App() 0

1

1

How many render() ?

App()

Todos()

Todos()

Todo()

App() 0

1

1

Update the state

How many render() ?

App()

Todos()

Todos()

Todo()

App() 1

1

1

How many render() ?

App()

Todos()

Todos()

Todo()

App() 1

1

1

New props from App?

How many render() ?

App()

Todos()

Todos()

Todo()

App() 1

2

1

How many render() ?

App()

Todos()

Todos()

Todo()

App() 1

2

2

WAIT A MINUTE…

SORT BY ORDERSet order as components are mounted

How many render() ?

App()

Todos()

Todos()

Todo()

App() 0

0

0

How many render() ?

App()

Todos()Todos()

Todo()

App() 0

0

0

How many render() ?

App()

Todos()Todos()

Todo()

App() 0

0

0

How many render() ?

App()

Todos()Todos()

Todo()

App() 0

0

0

Update the state

How many render() ?

App()

Todos()Todos()

Todo()

App() 1

0

0

How many render() ?

App()

Todos()Todos()

Todo()

App() 1

0

0

Update the state

How many render() ?

App()

Todos()Todos()

Todo()

App() 1

1

0

How many render() ?

App()

Todos()Todos()

Todo()

App() 1

1

1

How many render() ?

App()

Todos()Todos()

Todo()

App() 1

1

1

How many render() ?

App()

Todos()Todos()

Todo()

App() 1

1

1

Callback order in transaction

Todos.setState({ todos: [‘Uno’, ‘Dos’] }); App.setState({ title: ‘Bye’ }); Todos.setState({ todos: [‘Raz’, ‘Dva’] });

1. App setState 2. Todos setState 3. Todos setState

Callbacks order

Transactions In ReactPreserving input selection

Suppressing events during DOM work

Collecting “componentDidUpdate”

etc

FINAL WORDS

REACT IS COMPLICATED SO YOUR CODE DOES’T HAVE TO BE

http://redux-book.com

The Complete Redux Book

And read our blog:http://blog.500tech.com

Don’t <React />, Plan!