React性能优化思路
软件的性能优化思路就像生活中去看病,大致是这样的:
使用工具来分析性能瓶颈(找病根)
尝试使用优化技巧解决这些问题(服药)
使用工具测试性能是否确实有提升(疗效确认)
初识react只是为了尽快完成项目,后期进行代码审查时候发现有很多地方需要优化,因此做了个小结。
Code Splitting
shouldComponentUpdate避免重复渲染
使用不可突变数据结构
组件尽可能的进行拆分、解耦
列表类组件优化
bind函数优化
不要滥用props
ReactDOMServer进行服务端渲染组件
Code Splitting
Code Splitting 可以帮你“懒加载”代码,如果你没办法直接减少应用的体积,那么不妨尝试把应用从单个 bundle 拆分成单个 bundle + 多份动态代码的形式。
webpack提供三种代码分离方法,详情见
入口起点:使用 entry 配置手动地分离代码。
防止重复:使用 SplitChunks 去重和分离 chunk。
动态导入:通过模块的内联函数调用来分离代码。
在此,主要了解一下第三种动态导入的方法。
1、例如可以把下面的import方式
import { add } from './math'; console.log(add(16, 26));
改写成动态 import 的形式,让首次加载时不去加载 math 模块,从而减少首次加载资源的体积。
import("./math").then(math => { console.log(math.add(16, 26)); });
2、例如引用react的高阶组件react-loadable进行动态import。
import Loadable from 'react-loadable'; import Loading from './loading-component'; const LoadableComponent = Loadable({ loader: () => import('./my-component'), loading: Loading, }); export default class App extends React.Component { render() { return <LoadableComponent/>; } }
上面的代码在首次加载时,会先展示一个 loading-component,然后动态加载 my-component 的代码,组件代码加载完毕之后,便会替换掉 loading-component
shouldComponentUpdate避免重复渲染
当一个组件的props或者state改变时,React通过比较新返回的元素和之前渲染的元素来决定是否有必要更新实际的DOM。当他们不相等时,React会更新DOM。
在一些情况下,你的组件可以通过重写这个生命周期函数shouldComponentUpdate来提升速度, 它是在重新渲染过程开始前触发的。 这个函数默认返回true,可使React执行更新。
为了进一步说明问题,引用官网的图解释一下,如下图( SCU表示shouldComponentUpdate,绿色表示返回true(需要更新),红色表示返回false(不需要更新);vDOMEq表示虚拟DOM比对,绿色表示一致(不需要更新),红色表示发生改变(需要更新)):
根据渲染流程,首先会判断shouldComponentUpdate(SCU)是否需要更新。如果需要更新,则调用组件的render生成新的虚拟DOM,然后再与旧的虚拟DOM对比(vDOMEq),如果对比一致就不更新,如果对比不同,则根据最小粒度改变去更新DOM;如果SCU不需要更新,则直接保持不变,同时其子元素也保持不变。
C1根节点,绿色SCU、红色vDOMEq,表示需要更新。
C2节点,红色SCU,表示不需要更新,同时
C4、C5作为其子节点也不需要检查更新。
C3节点,绿色SCU、红色vDOMEq,表示需要更新。
C6节点,绿色SCU、红色vDOMEq,表示需要更新。
C7节点,红色SCU,表示不需要更新。
C8节点,绿色SCU,表示React需要渲染这个组件;绿色vDOMEq,表示虚拟DOM一致,不更新DOM。
因此,我们可以通过根据自己的业务特性,重载shouldComponentUpdate,只在确认真实DOM需要改变时,再返回true。一般的做法是比较组件的props和state是否真的发生变化,如果发生变化则返回true,否则返回false。引用官网的案例。
class CounterButton extends React.Component { constructor(props) { super(props); this.state = {count: 1}; } shouldComponentUpdate(nextProps, nextState) { if (this.props.color !== nextProps.color) { return true; } if (this.state.count !== nextState.count) { return true; } return false; } render() { return ( <button color={this.props.color} onClick={() => this.setState(state => ({count: state.count + 1}))}> Count: {this.state.count} </button> ); } }
在以上代码中,shouldComponentUpdate只检查props.color和state.count的变化。如果这些值没有变化,组件就不会更新。当你的组件变得更加复杂时,你可以使用类似的模式来做一个“浅比较”,用来比较属性和值以判定是否需要更新组件。这种模式十分常见,因此React提供了一个辅助对象来实现这个逻辑 - 继承自React.PureComponent。