react 性能优化
使用 shouldComponentUpdate
react 生命周期
从 react
的生命周期可以看出,当 component
的 props
和 state
改变时,会调用 shouldComponentUpdate
确认要不要刷新。默认 shouldComponentUpdate
都是返回 true
,这样 component
就会 re-render
。我们可以重写 shouldComponentUpdate
, 使之只在特定情况返回 true
,其他情况返回 false
,来避免不必要的 re-render
。
例子
比如组件的改变只依赖 props.color
或 state.count
,可以像下面这样写:
1 | class CounterButton extends React.Component { |
上面例子中,我们在 shouldComponentUpdate
中判断 props.color
和 state.count
前后有没变化,有就返回 true
, 没有就返回 false
,避免了不必要的重新渲染。
可是当依赖的属性很多时,手写 shouldComponentUpdate
就会变得很麻烦。幸运的是 react 给我们提供了偷懒的工具—— React.PureComponent
。当组件继承自 React.PureComponent
时,内部会自动帮我们检查 props
和 state
的所有字段前后有没发生变化,并决定要不要重新渲染,所以大部分情况不用再重写 shouldComponentUpdate
。
现在代码变成下面这样:
1 | class CounterButton extends React.PureComponent { |
属性内部保持不变性
使用 React.PureComponent
要注意的一点是在比较对象(object、array)时只比较引用,不对内部进行对比。看下面例子:
1 | class ListOfWords extends React.PureComponent { |
在 handleClick
使用 push , this.state.words 的内部发生变化,引用并没有变化,所以 setState 后 ListWords 不会刷新。解决办法如下:
1 | // 办法1 |
上面代码都会生成一个新的 words
数组对象,这样 ListOfWords
就能比较出 props.words
前后发生变化,进行重新渲染。
保持不可变(Immutability
)有以下好处:
- 我们可以对每个时间点的
props
和state
进行快照保存,这样就可以返回任意时间点的状态。在某些场景这非常有用,比如游戏中存档,文档编辑的 undo 和 redo。 - 让检测对象变化变得简单。对于可变对象的变化检测非常麻烦,要检测对象里的所有字段。而不可变对象的检测就很简单,只要检测前后引用是否发生变化。这点对于创建
React.PureComponent
是非常有用的。
Function Components
如果一个组件只有 render
方法,且没有 state
,那么可以使用 Function Components
。直接使用一个函数,入参为 props
,返回要渲染的内容。比如:
1 | function Square(props) { |
总结
react 的性能优化可以从四方面入手:
- 使用
shouldComponentUpdate
避免不必要重新渲染 - 如果对于相同的
props
和state
,render
返回的结果一样,那么就继承React.PureComponent
,避免重新渲染。 - 保持对象的不可变性(
Immutability
),减少对象比较的消耗。 - 对于只有
render
方法,且没有state
的组件使用Function Components
,减少一层封装。