Contents
1. 减少组件重复渲染
React.PureComponent最重要的一个用处就是优化React应用,这很容易快速地实现。使用React.PureComponent对性能的提升是非常可观的,因为它减少了应用中的渲染次数。
1 2 3 4 5 6 7 8 |
//现有实现 import React, { Component } from 'react' export default class CustomTemplateView extends Component {} //修改为 import React, { PureComponent } from 'react' export default class CustomTemplateView extends PureComponent {} |
说明:
- PureComponent改变了生命周期方法shouldComponentUpdate,并且它会自动检查组件是否需要重新渲染。这时,只有PureComponent检测到state或者props发生变化时,PureComponent才会调用render方法,因此,你不用手动写额外的检查,就可以在很多组件中改变state。
-
其中,shadowEqual只会”浅”检查组件的props和state,这就意味着
嵌套对象和数组是不会被比较的
。 -
对于PureCompnent组件,内层引用类型的数据节点变化,同时需要state和props的 root节点的引用地址改变。
2. 属性类型及默认值描述
为了后续有效的组件维护,要求React组件中,对Props属性进行检查,并赋予默认值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import React, { Component } from 'react' import PropTypes from 'prop-types' export default class ProfileContainer extends Component { static propTypes = { model: PropTypes.object.isRequired, title: PropTypes.string } static defaultProps = { model: { id: 0 }, title: 'Your Name' } state = { expanded: false } } |
3. Bundle的大小
以下两种打包结果,会有明显的size比对,具体实例可参考 Reduce Your bundle.js File Size
1 2 3 4 5 6 7 8 |
import { concat, sortBy, map, sample } from 'lodash' // vs. import concat from 'lodash/concat'; import sortBy from 'lodash/sortBy'; import map from 'lodash/map'; import sample from 'lodash/sample'; |
4. 容器性组件(container component)和展示性组件(presentational component)
使用React编写组件时,我们需要有意识地将组件划分为容器性组件(container component)和展示性组件(presentational component),这样有助于我们在编写组件时,更加明确这个组件应该负责哪些事情。
容器性组件【Container】和展示性组件【Presentational】可以相互嵌套,一个容器性组件可以包含多个展示性组件和其他的容器性组件;
一个展示性组将也可以包含容器性组件和其他的展示性组件。对于非常简单的页面,一般只要一个容器性组件就足够了;但对于复杂页面,则需要多个容器性组件,否则所有的业务逻辑都在一个容器性组件中处理的话,会导致这个组件非常复杂,同时这个组件获取到的源数据,可能需要经过很多层的组件Props的传递,才能到达最终使用的展示性组件。
5. 代码&语法优化
5.1 组件代码的可读性
所有组件应该有propTypes & defaultProps,便于其他开发人员使用该组件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import React, {Component} from 'react' import './styles/ProfileContainer.css' export default class ProfileContainer extends Component { static propTypes = { model: React.PropTypes.object.isRequired, title: React.PropTypes.string } static defaultProps = { model: { id: 0 }, title: 'Your Name' } state = { expanded: false } render() { return <div></div> } } |
5.2 绑定this指针的简捷语法
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import React, {Component} from 'react' import ExpandableForm from './ExpandableForm' import './styles/ProfileContainer.css' export default class ProfileContainer extends Component { handleExpand = (e) => { e.preventDefault() this.setState({ expanded: !this.state.expanded }) } render() { return <div onClick={this.handleExpand}></div> } } |
5.3 解构语法
让代码块,看起来清晰易读。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
render() { const {model, title} = this.props return ( <ExpandableForm onSubmit={this.handleSubmit} expanded={this.state.expanded} onExpand={this.handleExpand}> <div> <h1>{title}</h1> <input type="text" value={model.name} onChange={this.handleNameChange} placeholder="Your Name"/> </div> </ExpandableForm> ) } |
5.4 避免传递新的闭包到子组件
避免每次父组件渲染时,创建一个新的函数并传递给输入
1 2 3 4 5 6 7 8 |
<input type="text" value={model.name} // onChange={(e) => { model.name = e.target.value }} // ^ Not this. Use the below: onChange={this.handleChange} placeholder="Your Name"/> |
5.5 尽量多的使用函数组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import React from 'react' import {observer} from 'mobx-react' import './styles/Form.css' const expandableFormRequiredProps = { onExpand: React.PropTypes.func.isRequired, expanded: React.PropTypes.bool } function ExpandableForm({ onExpand, expanded = false, children }) { return ( <form style={ expanded ? { height: 'auto' } : { height: 0 } }> {children} <button onClick={onExpand}>Expand</button> </form> ) } ExpandableForm.propTypes = expandableFormRequiredProps export default ExpandableForm |
5.6 修饰器包装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
//柯里化函数 function observer(config) { return function(Component) { return <Component {...config} /> } } //函数包装 export default observer({watch: true})(React.Component) //class修饰器 @observer class ProfileContainer extends Component { } export default ProfileContainer |