react组件的生命周期

React组件的生命周期分为三个阶段:组件的创建阶段、组件的运行阶段、组件的销毁阶段

1.组件的创建阶段

//1.生命周期第一个执行的是静态属性(只会执行一次)
//  静态属性:设置props的初始值(在使用当前组件的时候,没有给当前组件传递props的时候,该初始值会生效)
static defaultProps = {
    initcount: 1000
}
static propTypes = {
    // 使用 prop-types 包 来定义 initcount 为 number 类型
    // isRequired 表示这个props属性是必须要传递的
    initcount: ReactTypes.number.isRequired
}

//2.生命周期第二个执行的是constructor 构造函数 (执行一次)
// 在创建组件对象的时候会自动调用构造函数
constructor(props) {
    console.log("constructor")
    super(props)
    //在构造函数中指定组件的私有数据
    this.state = {
        count: props.initcount
    }
    this.divRef = React.createRef()
}

//3.当子组件接收到新的props会执行,在react16.4版本以后,setState修改state数据之后也会触发这个方法(执行多次)
// 在该方法中不能通过this.setSate来修改state数据,因为在staic修饰的方法中就没有this
//作用:将传递的props映射到state里面
//参数: nextProps 外部传递过来的props属性
//      prevState 之前的state状态
static getDerivedStateFromProps(nextProps, prevState) {
    console.log("getDerivedStateFromProps", nextProps, prevState)
    //获取到父组件中传递过来的initcount值
    const { initcount } = nextProps;
    //当父组件中传递过来的initcount发生改变了
    if (initcount != prevState.prevCount) {
        //在方法中返回{count:initcount} 替换掉当前state中的 count值
        return {
            count: initcount,
            prevCount:initcount
        }
    }
    //如果父组件中传递过来的initcount没有变化,就返回一个空对象(此时不对当前的state做任何修改)
    return null
}

//4.创建虚拟dom,但是虚拟dom还没有挂载到页面 (执行多次)
// render函数中不能使用setState()来修改state的数据,因为会死循环
render() {
    console.log("render", this.divRef.current)  //null
    return (<div ref={this.divRef}>
        哈哈Counter {this.state.count}
    </div>)
}

//5.虚拟dom已经挂载到页面,此时可以获取到最新的页面 (执行一次)
componentDidMount() {
    console.log("componentDidMount", this.divRef.current, this.state)  //null
}

2.组件运行阶段

// 第一个会执行:static getDerivedStateFromProps
// 当父组件给子组件传递的props发生变化的时候,会执行该方法。
// 在react16.4版本以后,当前组件的state发生变化,会触发forceUpdate方法,然后还是会触发该方法

// 第二个会执行: shouldComponentUpdate
// 在这个函数中,我们可以设置指定条件下去更新页面,指定条件下不更新页面。这个函数中入参props和state都是最新的
// 在该方法中不能通过this.setSate来修改state数据
shouldComponentUpdate(nextProps, nextState) {
    console.log("shouldComponentUpdate", nextProps, nextState)
    // 在 shouldComponentUpdate 中要求必须返回一个布尔值
    // 在 shouldComponentUpdate 中,如果返回的值是 false,则不会继续执行后续的生命周期函数,而是直接退回到了运行中的状态,此时后续的render函数并没有被调用,因此页面不会被更新,但是组件的 state 状态,却被修改了;
    // return nextState.count % 2 == 0 ? true : false;
    return true;
}

//第三个会执行:render  此时会重新构建虚拟dom,但是新的虚拟dom还没有渲染到页面

//第四个会执行getSnapshotBeforeUpdate 函数
// 在该方法中不能通过this.setSate来修改state数据
getSnapshotBeforeUpdate() {
    console.log("getSnapshotBeforeUpdate")
    return {}
}

//第五个执行componentDidUpdate 函数
// 在该方法中不能通过this.setSate来修改state数据
//表示组件已经更新完毕  此时可以获取到最新的页面
componentDidUpdate() {
    console.log("componentDidUpdate", this.state)
}

3.组件的销毁阶段

1
2
3
componentWillUnmount() {
console.log("componentWillUnmount")
}
//很关键的,我们获取当前rootNode的scrollHeight,传到componentDidUpdate 的参数perScrollHeight
//在render方法调用之后,在componentDidUpdate之前执行,我们可以在这个方法中获取到元素的滚动位置的信息
//还可以在该方法中做一些样式的微调
getSnapshotBeforeUpdate() {
    //console.log(this.rootNode.clientHeight)
    //this.rootNode.style.backgroundColor = "red";
    return this.rootNode.scrollHeight;
}