Dive into React Performance

31
Dive into React Perf CT Wu, 2016 @ JSDC Twitter: wu_ct Github: wuct Email: [email protected]

Transcript of Dive into React Performance

Dive into React PerfCT Wu, 2016 @ JSDCTwitter: wu_ct Github: wuct Email: [email protected]

Better performance leads to better user experience

Use the production version of React

Use a bundler

<script src="path/to/react.min.js"></script><script src="path/to/react-dom.min.js"></script>

process.env.NODE_ENV = "production"

Use pre-built files

How does React work?

createElement(View, {}, [ createElement(View), createElement(View)])

<View> <View /> <View /></View>

{ type: View, props: { children: [ { type: View }, { type: View }, ] }}

ReactDOM.render( )

setState()

• Reduce call to React.createElement() • Avoid reconciliation • Avoid re-mounting

render() { return ( <table> <thead> <tr> <th>Header 1</th> <th>Header 2</th> </tr> </thead> <tfoot> <tr> <td>Footer 1</td> <td>Footer 2</td> </tr> </tfoot> <tbody> { // ... } </tbody> </table> )}

const headerAndFooter = <thead> <tr> <th>Header 1</th> <th>Header 2</th> </tr> </thead> <tfoot> <tr> <td>Footer 1</td> <td>Footer 2</td> </tr> </tfoot> render() { return ( <table> {headerAndFooter} <tbody> { // ... } </tbody> </table> )}

setState()

bailout

shoudComponentUpdate(nextProps, nextState) { if (/* You want to update */) { return true } return false}

Pure Render OptimizationshoudComponentUpdate(nextProps, nextState) { return ( !shallowEqual(nextProps, this.props) || !shallowEqual(nextState, this.state) )}

class extends React.PureComponent { // ...}

or

Anti Pure Render render() { return ( <PureComponent inlineFunc={() => {}} funcBind={func.bind(this)} arrayLiteral={[]} newArray={map(…)} objectLiteral={{}} newObject={assign({}, …)} > <NestedChild /> </PureComponent> ) }

Static View Optimization

import StaticContainer from 'react-static-container'

shoudComponentUpdate() { return false}

or

React Internal Bailout

• Bailout when prevElement === nextElement

• Don’t bailout when prevContext !== nextContext

• React always create a new context

• Don’t use setState() and getChildContext() in one component

class extends React.Component { getChildContext() { return this.state }

componentDidMount() { setInterval(() => this.setState({ time: this.state.time + 1 }) , 1000) }

// ...}

• Updating is faster than re-mounting

• Don’t change the key or the type if you want to update

render() { return isDarkTheme ? <DarkApp /> : <LightApp />}

render() { <App dark={isDarkTheme} />}

render () { return ( <List> { data.map(item => <Item key={item.uniqueId} /> ) } </List> )}

render () { return ( <List> { data.map(item => <Item key={Math.random()} /> ) } </List> )}

React Perf Tool• Currently, only supports the development version of

React

• Perf.start()

• Perf.stop()

• Perf.printWasted()

• Perf.printOperations()

class Child extends React.Component { render() { return <div /> }}

class App extends React.Component { state = { title: 'Foo' } render() { return ( <div> {this.state.title} <Child /> </div> ) }}

Perf.start()app.setState({ title: ‘bar’ })Perf.stop()Perf.printWasted()

class Child extends React.PureComponent { render() { return <div /> }}

Perf.start()app.setState({ title: ‘bar’ })Perf.stop()Perf.printWasted()

class App extends React.Component { state = { theme: 'light' }

render() { return ( <div> { this.state.theme === 'light' ? <Light /> : <Dark /> } </div> ) }}

Perf.start()app.setState({ theme: 'dark' })Perf.stop()Perf.printOperations()

class App extends React.Component { state = { theme: 'light' } render() { return ( <div> <Content theme={this.state.theme} /> </div> ) }}

Perf.start()app.setState({ theme: 'dark' })Perf.stop()Perf.printOperations()

React Fiber• Is still experimental

• Prioritization

• Return multiple elements from render

• Try it now:

npm i [email protected]

import ReactDOMFiber from 'react-dom/fiber'

Thanks!

• Github: wuct

• Twitter: wu_ct

[email protected]