七、性能优化
1,使用生产环境版本的库
对于create-react-app脚手架创建的项目,只需要执行npm run build,就会构建生产环境版本的React库。其原理是,一般第三方库都会根据process.env.NODE_ENV这个环境变量决定在开发环境和生产环境下执行的代码有哪些不同。当执行npm run build时,构建脚本会把NODE_ENV的值设置成production,也就是会以生产环境模式编译代码。
如果不是create-react-app脚手架创建的项目,而是完全自己编写Webpack的构建配置,那么在执行生产环境的构建时,就需要在webPack的配置项中包含以下插件的配置:
plugin: [ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify('production') } }), new UglifyJSPligin(); // ... ]
2,避免不必要的组件渲染
当组件的props和state发生变化时,组件的render方法会被调用,返回一个虚拟DOM对象。但是有些情况是不必要重新调用render的。例如父组件的每一次render调用都会触发子组件componentWillReceiveProps的调用,进而子组件的render也会被调用,但这时候子组件的props可能并没有改变,改变的是父组件的props和state,所以子组件的这一次render没有必要。
React生命周期方法中提供一个shouldConponentUpdate方法,默认返回值是true,如果返回false则停止更新,在这个方法中根据组件自身的业务逻辑决定返回true还是false,从而避免一切不必要的渲染。
shouldComponentUpdate(nextProps,nextState) { if(nextProps.item === this.props.item){ return false; } return true; }
即使两个对象的引用不相等,内容也可能是相等的。最精确的比较是遍历对象的每一层级的属性分别比较,也就是深比较,但shouldConponentUpdate被频繁调用,如果层次很深,对性能的影响很大。可以只比较对象的第一层级的属性,也就是浅比较,执行浅比较会使用===比较item.foo和nextItem.foo、item.bar和nextItem.bar,而不会继续比较foo和bar的内容。
React提供了一个PureComponent组件,这个组件会使用浅比较来比较新旧props和state,因此可以让组件继承PureComponent来替代手写shouldConponentUpdate的逻辑。
class Container extends React.PureComponent { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } handleClick() { const numbers = this.state.numbers; //直接修改numbers对象 numbers.push(numbers[numbers.length - 1] + 1); this.setState({numbers: numbers}); } render() { return ( <div> <button onClick={this.handleClick}></button> </div> ) } } export default Container;
点击button,不会重新调用render,因为handle是直接修改numbers数组(push修改原数组),this.state.numbers的引用在前后没有发生变化,所以shouldConponentUpdate返回false,终止更新。(把state当做不可变对象的重要原因就是为了提高组件state比较的效率。对于不可变对象来说,只需要比较对象的引用即可。)
3,使用key
见上一篇。