如何观察React的性能
可以使用react自带的Component Profiling工具,在页面的url后面添加"?react_perf",就可以在chrome的调试器里面使用Performance tab页记录性能。
如何优化性能
通过观察性能的瓶颈,我们找出可以优化的地方。仔细分析瓶颈产生的原因,我们而已借助高阶函数HOC 给想要优化的组件添加console.log().
观察组件是否被重新渲染?
我们知道,组件重新渲染的代价比较高。尤其是包含很多子组件的外层组件,那么我们可以在外层组件渲染的时候打印出来。实现方法:
// in src/log.jsconst log = BaseComponent => props => { console.log(`Rendering ${BaseComponent.name}`); return;}export default log;// in src/MyComponent.jsimport log from './log';export default log(MyComponent);复制代码
这样我们可以观察组件是否频繁被重新渲染。
提取component,使用shouldComponentUpdate
有的时候父组件的一部分内容可以提取一个子组件出来。然后我们观察这个子组件是否具有独立的更新特征,当子组件的数据没有变化的时候,我们使用 shouldComponentUpdate 来避免不必要的重新渲染。
当使用shouldComponentUpdate 方法的时候,我们可以考虑使用PureComponent。 注意PureComponent使用的是浅比较(===)。Recompose
是一个React的工具库,提供了大量的函数式组件和高阶组件。帮助你简化定义React 组件,使用类似纯函数组件定义出普通的React组件。具体的api参考官网。
Redux
当你使用Redux的时候,connect的Component默认是PureComponent方式,你所要做的是Redux判断组件的props是否相等,用的是===,所以要注意可变对象和不可变对象的合理使用。在reducers里面一定要使用不可变对象定义方式修改全局state,这样才能真正重新选择组件。
reselect
为了避免Redux在connect的时候不必要的重新render,要确保mapStateToProps方法在调用的时候不会产生一个新的object。例如不要再用{...object} 或者Object.assign()定义一个新的对象。
进一步可以使用库。注意JSX的写法
在JSX中避免使用{
{}}方式直接定义object。因为这种方式每次都会产生一个新数据。//badimport React from 'react';import MyTableComponent from './MyTableComponent';const Datagrid = (props) => (... )//goodimport React from 'react';import MyTableComponent from './MyTableComponent';const tableStyle = { marginTop: 10 };const Datagrid = (props) => (... )复制代码
// badconst MyComponent = (props) =>{React.cloneElement(Foo, { bar: 1 })};// goodconst additionalProps = { bar: 1 };const MyComponent = (props) =>{React.cloneElement(Foo, additionalProps)};复制代码
当一个父组件中有纯函数定义的组件时,合理使用compose的onlyUpdateForKeys。避免子组件不必要的重新render。
import { CardActions } from 'material-ui/Card';import { CreateButton, RefreshButton } from 'admin-on-rest';import onlyUpdateForKeys from 'recompose/onlyUpdateForKeys';const Toolbar = ({ basePath, refresh }) => ();export default onlyUpdateForKeys(['basePath', 'refresh'])(Toolbar);复制代码
结语
使用React开发项目,每当遇到性能瓶颈的时候,首先使用react-addons-perf来观察瓶颈出现的地方,然后借助辅助工具抽丝剥茧找出问题根源。最后使用shouldComponentUpdate等方式避免不必要的组件render,这种方式是最有效的。但是也要注意很小的组件调用pure()方法的开销可能比重新渲染还要大,所以不要过度使用。