React v16.4 的生命周期

React v16废弃的三个生命周期函数
  • componentWillMount : 组件初始化时调用,整个生命周期只调用一次,此时可以修改state。
  • componentWillReceiveProps(nextProps):当props发生变化的时候调用
  • componentWillUpdate :组件数据更新前调用,此时可以更改state。

React v16后为什么会废弃这三个生命周期函数?
由于React后期版本推出Fiber(异步渲染),在dom被挂载之前的阶段都可以被重新打断重来,导致componentWillMount、componentWillReceiveProps、componentWillUpdate在一次更新中可能会被执行多次

React v16 后新增的2个生命周期函数
  • static getDerivedStateFromProps : 与componentDidUpdate配合使用,可以覆盖componentWillReceiveProps的所有用法。
  • getSnapshotBeforeUpdate:与componentDidUpdate配合使用,可以覆盖componentWillUpdate的所有用法。
React v16的生命周期
  • 挂载阶段
  • 更新阶段
  • 卸载阶段
挂载阶段

挂载阶段也可以理解为组件的初始化阶段,就是将我们的组件插入到DOM中,只会发生一次。

  • constructor:组件构造函数,第一个被执行,我们通常在构造函数里初始化state对象或者给自定义方法绑定this。
constructor(props) {
    super(props)
    
    this.state = {
      select,
      height: 'atuo',
      externalClass,
      externalClassText
    }

    this.handleChange1 = this.handleChange1.bind(this)
    this.handleChange2 = this.handleChange2.bind(this)
}

禁止在构造函数中调用setState,可以直接给state设置初始值

  • static getDerivedStateFromProps(nextProps, prevState) :这是一个静态方法,所以不能在这个函数里面使用this,这个函数有2个参数nextProps、prevState,分别指接收到的新参数和当前的state对象,这个函数返回一个对象用来更新当前的state对象,如果不需要更新可以返回null.当我们接收到新的属性想去修改我们的state,可以使用该函数
class ExampleComponent extends React.Component {
  state = {
    isScrollingDown: false,
    lastRow: null
  }
  static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.currentRow !== prevState.lastRow) {
        return {
            isScrollingDown:
            nextProps.currentRow > prevState.lastRow,
            lastRow: nextProps.currentRow
        }
    }
    return null
  }
}

  • render:render函数是纯函数,只返回需要渲染的东⻄,不应该包含其它的业务逻辑,可以返回原⽣的DOM、React 组件、Fragment、Portals、字符串和数字、Boolean和null等内容。

  • componentDidMount:组件装载之后调用,此时我们可以获取到DOM节点并操作,比如对canvas,svg的操作,服务器请求,订阅都可以写在这个里面,但是记得在componentWillUnmount中取消订阅。

componentDidMount() {
    const { progressCanvas, progressSVG } = this

    const canvas = progressCanvas.current
    const ctx = canvas.getContext('2d')
    canvas.width = canvas.getBoundingClientRect().width
    canvas.height = canvas.getBoundingClientRect().height

    const svg = progressSVG.current
    const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')
    rect.setAttribute('x', 0)
    rect.setAttribute('y', 0)
    rect.setAttribute('width', 0)
    rect.setAttribute('height', svg.getBoundingClientRect().height)
    rect.setAttribute('style', 'fill:red')

    const animate = document.createElementNS('http://www.w3.org/2000/svg', 'animate')
    animate.setAttribute('attributeName', 'width')
    animate.setAttribute('from', 0)
    animate.setAttribute('to', svg.getBoundingClientRect().width)
    animate.setAttribute('begin', '0ms')
    animate.setAttribute('dur', '1684ms')
    animate.setAttribute('repeatCount', 'indefinite')
    animate.setAttribute('calcMode', 'linear')
    rect.appendChild(animate)
    svg.appendChild(rect)
    svg.pauseAnimations()

    this.canvas = canvas
    this.svg = svg
    this.ctx = ctx
 }

在componentDidMount中调用setState会触发一次额外的渲染,多调用一次render函数,但是用户对此没有感知,因为它时在浏览器刷新屏幕前执行的,但是我们应该在开发中避免它,因为它会带来一定的性能问题,我们应该在constructor中初始化我们的state对象,而不应该在componentDIdMount调用state方法。

更新阶段

更新阶段,当组件的props改变了,或组件内部调用了setState或者forceUpdate发生,会发生多次。

  • getDerivedStateFromProps:这个方法在更新阶段也会触发。记住无论我们接收到的新的属性,调用了setState还是forceUpdate,这个方法都会被触发。

  • shouldComponentUpdate(nextProps, nextState):有两个参数nextProps和nextState,表示 新的属性和变化之后的state,返回⼀个布尔值,true表示会触发重新渲染,false表示不会触发重新渲染,默认返回 true,我们通常利⽤此⽣命周期来优化React程序性能 。
    注意当我们调用forceUpdate并不会触发该方法。因为默认时返回true,也就是只有接收到新的属性和调用了setState都会触发重新的渲染,这会带来一定的性能问题,所以我们需要将this.props和nextprops以及this.state和nextState进行比较来决定是否返回false,来减少重新渲染。
    但是官方提倡我们使用PureComponent来减少重新渲染的次数而不是手动编写shouldComponentUpdate代码,具体该怎么选择,全凭开发者自己选择。

  • render:更新阶段也会触发,这里不再

  • getSnapshotBeforeUpdate(prevProps, prevState):这个⽅法在render之后, componentDidUpdate之前调⽤,有两个参数prevProps和prevState,表示之前的属性和之前的state,这个函数有 ⼀个返回值,会作为第三个参数传给componentDidUpdate,如果你不想要返回值,可以返回null,此⽣命周期必须 与componentDidUpdate搭配使⽤。

class ScrollingList extends React.Component {
  constructor(props) {
    super(props);
    this.listRef = React.createRef();
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    // Are we adding new items to the list?
    // Capture the scroll position so we can adjust scroll later.
    if (prevProps.list.length < this.props.list.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    // If we have a snapshot value, we've just added new items.
    // Adjust scroll so these new items don't push the old ones out of view.
    // (snapshot here is the value returned from getSnapshotBeforeUpdate)
    if (snapshot !== null) {
      const list = this.listRef.current;
      list.scrollTop = list.scrollHeight - snapshot;
    }
  }

  render() {
    return (
      <div ref={this.listRef}>{/* ...contents... */}</div>
    );
  }
}

  • componentDidUpdate(prevProps, prevState, snapshot):该方法在getSnapshotBeforeUpdate方法之后被调用,有三个参数prevProps,prevState,snapshot,表示之前的props,之前的state,和snapshot。第三个参数是getSnapshotBeforeUpdate返回的。在这个函数里我们可以操作DOM,和发起服务器请求,还可以setState,但是注意一定要用if语句控制,否则会导致无限循环。
卸载阶段
  • componentWillUnmount:当我们的组件被卸载或者销毁了就会调用,我们可以在这个函数里去清除一些定时器,取消网络请求,清理无效的DOM元素等垃圾清理工作。注意不要在这个函数里去调用setState,因为组件不会重新渲染了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值