shouldComponentUpdate优化小技巧

随着项目的推进,页面组件越来越多,越来越细。当我们在父组件setState时,可能都会导致若干子组件进行无效的render。因此解决这个问题是我们学习的目的。

shouldComponentUpdate做了什么?

3942143032-5b5a70dfdc45c_fix732.jpg

使用shouldComponentUpdate可以让React知道当前状态或属性的改变是否不影响组件的输出,默认返回ture,返回false时不会重写render,而且该方法并不会在初始化渲染或当使用forceUpdate时被调用,我们要做的只是这样:

shouldComponentUpdate(nextProps, nextState) {
  return this.props.someData === nextProps.someData
}
复制代码

当时我们每次都要写如上的代码是不是很烦,因此React为我们提供了PureComponent

PureComponent

PureComponentComponent几乎完全相同,但PureComponent通过propsstate的浅对比来实现 shouldComponentUpate。如果对象包含复杂的数据结构,它可能会因深层的数据不一致而产生错误的否定判断(表现为对象深层的数据已改变视图却没有更新)

import { Component, PureComponent } from 'react'

class Parent extends Component {
  state = {
    title: '我是改变的内容',
    name: '张三'
  }

  handleChangeTitle() {
    this.setState({ title: '我已经改变' })
  }

  handleChangeName() {
    this.setState({ name: '李四' })
  }

  render() {
    return (
      <>
        <div onClick={this.handleChangeTitle.bind(this)}>{this.state.title}</div>
        <div onClick={this.handleChangeName.bind(this)}>改变children的值</div>
        <Child name={this.state.name} />
      </>
    )
  }
}

class Child extends PureComponent {
  render() {
    console.log('child is render....')
    return (
      <div>我是子组件的名称:{this.props.name}</div>
    )
  }
}

复制代码

当触发handleChangeTitle方法时,render方法并没有被触发。当触发handleChangeName方法时,render方法被触发,完美,但是如果传给Childprops不是String, Number等这种基本类型,而是类似于Object复杂类型呢?

import { Component, PureComponent } from 'react'

class Parent extends Component {
  state = {
    title: '我是改变的内容',
    user: { name: '张三' }
  }

  handleChangeTitle() {
    this.setState({ title: '我已经改变' })
  }

  handleChangeName() {
    let { user } = this.state
    user.name = '李四'
    this.setState({ user })
  }

  render() {
    return (
      <>
        <div onClick={this.handleChangeTitle.bind(this)}>{this.state.title}</div>
        <div onClick={this.handleChangeName.bind(this)}>改变children的值</div>
        <Child name={this.state.name} />
      </>
    )
  }
}

class Child extends PureComponent {
  render() {
    console.log('child is render....')
    return (
      <div>我是子组件的名称:{this.props.user.name}</div>
    )
  }
}
复制代码

这个时候,我们发现触发handleChangeName时,render并没有触发,界面也没有渲染,why?
这是因为state中user对象的引用并没有改变。有人说,我们在handleChangeName改变user的引用,然后PureComponent判断不就正确了吗?

this.setState({ user: { name: '李四' } })
复制代码

我们工作中,大部分传入的对象可能是这样的user: { name: '张三', age: 26, sex: '南', work: '码畜', ... },这个时候你想改变引用就不太合适了。那我们有啥解决方案呢?

immutable.js

immutable是一种持久化数据。一旦被创建就不会被更改。修改immutable对象的时候,将返回新的immutable,且原数据不会改变。immutable数据实现了结构共享:只会影响你改变的节点以及他的父节点,其他节点共享,从而达到了节省性能的目的。

import { Component, PureComponent } from 'react'
import { fromJS } from 'immutable'

class Parent extends Component {
  state = {
    title: '我是改变的内容',
    user: fromJS({ name: '张三' })
  }

  handleChangeTitle() {
    this.setState({ title: '我已经改变' })
  }

  handleChangeName() {
    let { user } = this.state
    user = user.set('name', '李四')
    this.setState({ user })
  }

  render() {
    return (
      <>
        <div onClick={this.handleChangeTitle.bind(this)}>{this.state.title}</div>
        <div onClick={this.handleChangeName.bind(this)}>改变children的值</div>
        <Child name={this.state.name} />
      </>
    )
  }
}

class Child extends PureComponent {
  render() {
    console.log('child is render....')
    const user = this.props.user.toJS()
    return (
      <>
        <div>我是子组件的名称:{this.props.user.get('name')}</div>
        <div>我是子组件的名称:{user.name}</div>
      </>
    )
  }
}
复制代码

happy hacking

相关链接:
immutable: juejin.cn/post/697679…

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享