react生命周期和setState异步执行问题

什么是生命周期?

生命周期是一个组件从建立到销毁的过程。react会在不一样的时间点注入相应的钩子函数,以便于开发者进行更灵活的数据处理。react

生命周期只存在于类组件中,函数组件没有生命周期。可是在后来的新版本react提供了hooks用于管理函数组件的状态。

生命周期分三个阶段

  1. 初始化阶段;
  2. 更新阶段;
  3. 销毁阶段。

初始化阶段:

微信截图_20200210201325.png

  1. constructor(props)函数:ajax

    • 只会执行一次,用于初始化数据;
    • 没法使用setState,页面还未挂载。
  2. componentWillMount函数:数组

    • 挂载数据以前执行,只会执行一次;
    • 可使用setState,可是很容易致使bug,不建议在这里使用;
    • 新版的react已经移除该钩子函数。
  3. render函数:性能优化

    • 每次渲染都会运行;
    • 将返回数据挂载在虚拟dom中,而后会构建真实的dom渲染页面;
    • 不能调用setState方法,会形成无限递归内存泄露。
  4. componentDidMount函数:微信

    • 挂载完成阶段,能够在这里开启定时器,发送ajax请求业务数据等。

更新阶段:属性(props)发生变化或者状态(state)发生变化

微信截图_20200210201404.png

  1. componentWillReceiveProps(nextProps)函数:dom

    • 接受新的属性值;
    • 使用该函数很容易致使一些bug,不建议使用。
    • 新版的react已经移除该钩子函数。
  2. shouldComponentUpdate(nextProps, nextState)函数:异步

    • 必须返回一个布尔值,返回true执行render函数,返回false不执行render函数;
    • 用于减小没必要要的渲染,作页面性能优化。
  3. componentWillUpdate(nextProps, nextState)函数:函数

    • 组件即将被从新渲染;
    • 新版的react已经移除该钩子函数。
  4. componentDidUpdate(prevProps, prevState, snapshot)函数:性能

    • 有时会在该函数中操做真实dom元素。

销毁阶段:

  1. componentWillUnmount()函数:优化

    • 只执行一次,在组件销毁前执行;
    • 一般在该函数中作一些清理计时器,中断请求的事情。

新版生命周期(16.3以上版本)

官方图解已经画的很清楚了,这里不在赘述,主要说一下区别。

移除钩子函数

  1. componentWillMount函数

    • 有一些bug难以解决,因此被移除。
  2. componentWillReceiveProps函数

    • 防止用户滥用,致使数据来源混乱不可控,相似手表定律一个页面的值要么来自属性要么来自状态,必须是单一的,不然是一种反模式的写法,容易形成bug。
  3. componentWillUpdate函数

    • 使用场景很少,因此被移除。

新增钩子函数

  1. getDerivedStateFromProps(props, state)函数

    • 是一个静态函数,使用是要加static关键字;
    • 在render以前调用;
    • 返回的值替换原来的state,返回null不改变state的值;
    • 多用于受控组件编写。
  2. getSnapshotBeforeUpdate(prevProps, prevState)函数

    • 真实的dom发生改变,可是还没渲染到页面中,能够进行一些dom操做;
    • 一般和componentDidUpdate(prevProps, prevState, snapshot)连用,返回的值做为该函数的第三个参数传入。

setState是异步的吗?

  1. 可能是异步的,当setSate在dom事件处理函数中调用时就是异步的;
  2. 异步会致使当前的状态更新不许确的问题。

举个例子:

import React, {Component} from 'react'

export default class index extends Component{
    state = {
        count: 0
    }
    
    //点击一次count加2
    hanldeClick = () => {
        this.State({
            count: this.state.count + 1
        })
        this.State({
            count: this.state.count + 1
        })
    }
    
    render(){
        return (
            <div onClick={this.hanldeClick}>{this.state.count}</div>
        )
    }
}

根据上述代码,在点击div以后,按道理,count的值应该变成2,但实际显示的确是1

解决办法:给setState传入一个函数更新数据。

//点击一次count加2
hanldeClick = () => {
    //使用这种方式获取的上一个state是最新的
    this.State(function(state, props) {
        return {
            count: state.count + 2
        };
    })
}
为何会形成这种现象?

react团队以为,dom事件处理函数中状态处理会比较复杂,setState的次数比较多,若是每次setState就去更新页面,会影响页面渲染效率,因此会将事件中的多个setState合并成同一个。

相关文章
相关标签/搜索