跳到主要内容

React 性能优化(高级)

性能优化对于 React 更加重要

  • shouldComponentUpdate(简称 SCU)
  • PureComponent 和 React.memo
  • 不可变值 immutable.js

shouldComponentUpdate

SCU 基本用法

shouldComponentUpdate(nextProps, nextState, nextContext) {
if (nextState.count !== this.state.count) {
return true // 可以渲染
}
return false // 不重复渲染
}

SCU 默认返回 true

父组件有更新,子组件则无条件也更新

// 子组件
class Footer extends React.Component {
constructor(props) {
super(props);
}

render() {
return <p>
{this.props.text}
</p>
}

componentDidUpdate() {
// 当更新父组件时,会一直执行此
console.log('footer add update')
}

// shouldComponentUpdate 默认返回 true
shouldComponentUpdate(nextProps, nextState, nextContext) {
if (nextProps.text !== this.props.text) {
return true // 可以渲染
}
return false // 不重复渲染
}

// React 默认:父组件有更新,子组件则无条件也更新
// 性能优化对于 React 更加重要
}

// 父组件
class TodoListDemo extends React.Component {
constructor(props) {
super(props);
this.state = {
footerInfo: '底部文字'
}
}

render() {
return <div>
<Footer text={this.state.footerInfo}/>
</div>
}
}

SCU 每次都要吗?

  • 需要时才优化,比如上面的例子
  • 一定要配合不可变值,比如下面的例子

例子

// 子组件
class List extends React.Component {
constructor(props) {
super(props);
}

render() {
// 子组件接收参数
const {list} = this.props

return <ul>
{list.map((item, index) => {
return <li key={item.id}>
<span>{item.title}</span>
</li>
})}
</ul>
}

// 增加 shouldComponentUpdate
shouldComponentUpdate(nextProps, nextState, nextContext) {
// lodash.isEqual 做对象或者数组的深度比较
if (lodash.isEqual(nextProps.list, this.props.list)) {
// 相等,则不重复渲染
return false
}
return true // 不相等,则渲染
}
}

SCU 使用总结

  • SCU 默认返回 true,即 React 默认重新渲染所有子组件
  • 必须配合“不可变值”一起使用
  • 可先不用 SCU,有性能问题时再考虑使用

PureComponent 和 memo

  • PureComponent,SCU 中实现了浅比较
  • memo,函数组件中的 PureComponent
  • 浅比较已适用大部分情况(尽量不要做深度比较)

PureComponent 例子

class PureComponentDemo extends React.PureComponent{
constructor(props) {
super(props);
}

shouldComponentUpdate() {
// 浅比较
}
}

memo 例子

function MyComponent(props) {
// 使用 props 渲染
}

function areEqual(prevProps, nextProps) {
// 如果把 nextProps 传入 render 方法的返回结果
// 与将 prevProps 传入 render 方法的返回结果一致的话则返回 true,
// 否则返回 false
}

export default React.memo(MyComponent, areEqual)

使用 immutable.js

  • 彻底拥抱“不可变值”
  • 基于共享数据(不是深拷贝),速度好
  • 有一定学习和迁移成本,按需使用

例子

const map1 = Immutable.Map({a: 1, b: 2, c: 3})
const map2 = map1.set('b', 50)
console.log(map1.get('b')) // 2
console.log(map2.get('b')) // 50