【系列化】reactJS项目构建3--react性能优化方案及demo
发布在reactJS2017年11月17日view:271性能优化React
在文章任何区域双击击即可给文章添加【评注】!浮到评注点上可以查看详情。

性能检测

安装 react 性能检测工具 npm i react-addons-perf --save ,然后在 ./app/index.jsx 中使用。

// 性能测试
import Perf from 'react-addons-perf'
if (__DEV__) {
    window.Perf = Perf
}

运行程序。在对页面操作之前先在网页的console中运行 Perf.start() 开始检测,然后进行若干操作。运行 Perf.stop() 停止检测,然后再运行 Perf.printWasted() 即可打印出浪费性能的组件列表。在项目开发过程中,要经常使用检测工具来看看性能是否正常。

如果性能的影响不是很大,例如每次操作浪费几毫秒、十几毫秒,个人认为没必要深究,但是如果浪费过多影响了用户体验,就必须去搞定它。


PureRenderMixin 优化

React 最基本的优化方式是使用PureRenderMixin,安装工具 npm i react-addons-pure-render-mixin --save 然后在组件中引用并使用。

import React from 'react'
import PureRenderMixin from 'react-addons-pure-render-mixin'

class List extends React.Component {
    constructor(props, context) {
        super(props, context);
        this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
    }
    //...省略其他内容...
}

React 有一个生命周期 hook 叫做 shouldComponentUpdate,组件每次更新之前,都要过一遍这个函数,如果这个函数返回true则更新,如果返回false则不更新。

而默认情况下,这个函数会一直返回true,就是说,如果有一些无效的改动触发了这个函数,也会导致无效的更新

那么什么是无效的改动?之前说过,组件中的props和state一旦变化会导致组件重新更新并渲染,但是如果props和state没有变化也莫名其妙的触发更新了呢(这种情况确实存在)—— 这就导致了无效渲染.

这里使用

this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);

的意思是重写组件的 shouldComponentUpdate 函数,在每次更新之前判断props和state,如果有变化则返回true,无变化则返回false。


简单的todolist-Demo

先实现一个简单的demo,在input中输入字符串,敲回车后,会在input框下方叠加显示输入的内容,点击显示的字符串,点击的字符串消失。

先看下文件流分布: enter image description here

index.tmpl.html 是个简单的html容器,只有一个id名为root的div,这里不多费口舌了。

* ./app/index.jsx
import React from 'react'
import { render } from 'react-dom'

import Todo from './containers/Todo';

// 性能测试
import Perf from 'react-addons-perf'
if (__DEV__) {
    window.Perf = Perf
}

render(
    <Todo/>,
    document.getElementById('root')
)
* ./app/containers/Todo/index.jsx
import React from 'react'
import PureRenderMixin from 'react-addons-pure-render-mixin'

import Input from '../../components/Input'
import List from '../../components/List'

export default class Todo extends React.Component {
    constructor(props, context) {
        super(props, context);
        this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
        this.state = {
            todos: []
        }
    }
    render() {
        return (
            <div>
              <Input submitFn={this.submitFn.bind(this)}/>
              <List todos={this.state.todos} deleteFn={this.deleteFn.bind(this)}/>
            </div>
        )
    }
    submitFn(value) {
        const id = this.state.todos.length
        this.setState({
            todos: this.state.todos.concat({
                id: id,
                text: value
            })
        })
    }
    deleteFn(id) {
        let data = this.state.todos
        this.setState({
            todos: data.filter(item => {
                if (item.id !== id) {
                    return item
                }
            })
        })
    }
}
* ./app/components/Input/index.jsx
import React from 'react'
import PureRenderMixin from 'react-addons-pure-render-mixin'

export default class Input extends React.Component {
    constructor(props, context) {
        super(props, context);
        this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
        this.state = {
            value: ''
        }
    }
    render() {
        return (
            <div>
               <input 
                    style={{width: '100%', height: '40px', fontSize: '35px'}}
                    value={this.state.value} 
                    onChange={this.changeHandler.bind(this)} 
                    onKeyUp={this.keyUpHandler.bind(this)}
                />
            </div>
        )
    }
    changeHandler(e) {
        // 实时同步数据
        this.setState({value: e.target.value})
    }
    keyUpHandler(e) {
        const value = this.state.value
        if (e.keyCode === 13 && value.trim()) {
            // 提交并清空数据
            this.props.submitFn(value)
            this.setState({value: ''})
        }
    }
}
* ./app/components/List/index.jsx
import React from 'react'
import PureRenderMixin from 'react-addons-pure-render-mixin'

class List extends React.Component {
    constructor(props, context) {
        super(props, context);
        this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
    }
    render() {
        const data = this.props.todos

        return (
            <ul style={{marginTop: '10px', fontSize: '20px', lineHeight: '30px'}}>
                {data.map((item, index) => {
                    return <li key={index} onClick={this.clickHandler.bind(this, item.id)}>{item.text}</li>
                })}
            </ul>
        )
    }
    clickHandler(id) {
        this.props.deleteFn(id)
    }
}

在input框中输入字符串之前, 可以试试用react性能检测工具Perf来检测代码的性能耗时。

评论
发表评论
暂无评论
WRITTEN BY
娜娜娜娜
本人已懒到爆……
TA的新浪微博
PUBLISHED IN
reactJS

我竟然还会这个~

我的收藏