React生命周期浅析

534

在这里插入图片描述 一、React组件生命周期

1、constructor constructor参数接受两个参数props,context 可以获取到父组件传下来的的props,context,如果你想在constructor构造函数内部(注意是内部哦,在组件其他地方是可以直接接收的)使用props或context,则需要传入,并传入super对象。

constructor(props,context) {
    super(props,context)
    console.log(this.props,this.context) // 在内部可以使用props和context
}

关于ES6的class constructor和super 只要组件存在constructor,就必须要写super,否则this指向会错误

constructor() {
    console.log(this) // 报错,this指向错误
}

2、componentWillMount 组件将要挂载

组件刚经历constructor,初始完数据 组件还未进入render,组件还未渲染完成,dom还未渲染 在组件挂载之前调用,且全局只调用一次。如果在这个钩子里可以setState,render后可以看到更新后的state,不会触发重复渲染。该生命周期可以发起异步请求,并setState。(React v16.3后废弃该生命周期,可以在constructor中完成设置state) 但是这里有一个问题

ajax请求建议写在willmount里吗? :答案是不推荐,别这么写

虽然有些情况下并不会出错,但是如果ajax请求过来的数据是空,那么会影响页面的渲染,可能看到的就是空白。 不利于服务端渲染,在同构的情况下,生命周期会到componentwillmount,这样使用ajax就会出错

3、componentDidMount 组件渲染完成

在组件挂载完成后调用,且全局只调用一次,在该生命周期函数内: 1.可以在这里使用refs,获取真实dom元素 2.组件第一次渲染完成,此时dom节点已经生成,可以在这里调用ajax请求,返回数据setState后组件会重新渲染

4、componentWillReceiveProps (nextProps)

componentWillReceiveProps在接受父组件改变后的props需要重新渲染组件时用到的比较多 它接受一个参数

1.nextProps 通过对比nextProps和this.props,将nextProps setState为当前组件的state,从而重新渲染组件

componentWillReceiveProps (nextProps) { 
    nextProps.openNotice !== this.props.openNotice && this.setState({
        openNotice:nextProps.openNotice 
    },() => { 
        console.log(this.state.openNotice:nextProps) //将state更新为nextProps,在setState的第二个参数(回调)可以打印出新的state 
    }) 
}

5、shouldComponentUpdate(nextProps,nextState)

组件挂载之后,每次调用setState后都会调用shouldComponentUpdate判断是否需要重新渲染组件。默认返回true,需要重新render。返回false则不触发渲染。在比较复杂的应用里,有一些数据的改变并不影响界面展示,可以在这里做判断,优化渲染效率。

因为react父组件的重新渲染会导致其所有子组件的重新渲染,这个时候其实我们是不需要所有子组件都跟着重新渲染的,因此需要在子组件的该生命周期中做判断

对于react初学者,可能涉及这个生命周期的机会比较少,但是如果你的项目开始注重性能优化,随着你对react的喜爱和深入,你就会用到这个生命周期

shouldComponentUpdate(nextProps,nextState){
    console.log("---组件接受到重绘状态---")
    if(this.props != nextProps || this.state != nextState)
    return true
}

6、componentWillUpdate (nextProps,nextState)

shouldComponentUpdate返回true或者调用forceUpdate之后,componentWillUpdate会被调用。 不能在该钩子中setState,会触发重复循环。 这里同样可以拿到nextProps和nextState。

7、render函数

render函数会插入jsx生成的dom结构,react会生成一份虚拟dom树,在每一次组件更新时,在此react会通过其diff算法比较更新前后的新旧DOM树,比较以后,找到最小的有差异的DOM节点,并重新渲染

react16中 render函数允许返回一个数组,单个字符串等,不在只限制为一个顶级DOM节点,可以减少很多不必要的div

意思你现在可以这样:

render () {
  return " "
}
或者这样:

render () {
    return [
            <div></div>
            <div></div>
        ]
}

注意:尽量不要在render方法里面修改state,可能会触发死循环导致栈溢出。

8、componentDidUpdate(prevProps,prevState)完成组件渲染

除了首次render之后调用componentDidMount,其它render结束之后都是调用componentDidUpdate。 该钩子内setState有可能会触发重复渲染,需要自行判断,否则会进入死循环 一般情况下:里面有定时器和异步请求时不会出现死循环。

componentDidUpdate() {
    if(condition) {
        this.setState({..}) // 设置state
    } else {
        // 不再设置state
    }
}

9、componentWillUnmount ()

组件被卸载的时候调用。一般在componentDidMount里面注册的事件需要在这里删除。像在didmount里面设置的定时器可以在这里面进行清除。

二、react v16.3删掉以下三个生命周期

1、componentWillMount() 组件挂载之前 2、componentWillReceiveProps(nextProps) props即将变化之前 3、componentWillUpdate(nextProps, nextState) shouldComponentUpdate返回true或者调用forceUpdate之后,componentWillUpdate会被调用。

三、react v16.3 新加入的生命周期

1、static getDerivedStateFromProps 触发时间:在组件构建之后(虚拟dom之后,实际dom挂载之前) ,以及每次获取新的props之后。 每次接收新的props之后都会返回一个对象作为新的state,返回null则说明不需要更新state. 配合componentDidUpdate,可以覆盖componentWillReceiveProps的所有用法

class Example extends React.Component {
    static getDerivedStateFromProps(nextProps, prevState) {
        // 没错,这是一个static
    }
}

2、getSnapshotBeforeUpdate 触发时间: update发生的时候,在render之后,在组件dom渲染之前。 返回一个值,作为componentDidUpdate的第三个参数。 配合componentDidUpdate, 可以覆盖componentWillUpdate的所有用法。

class Example extends React.Component {
    getSnapshotBeforeUpdate(prevProps, prevState) {
        // ...
    }
}

四、完整的生命周期示例

class LifeCycle extends React.Component {
    constructor(props) {
        super(props);
        this.state = {str: "hello"};
    }
    componentWillMount() {
        alert("componentWillMount");
    }
    componentDidMount() {
        alert("componentDidMount");
    }
    componentWillReceiveProps(nextProps) {
        alert("componentWillReceiveProps");
    }
    shouldComponentUpdate() {
        alert("shouldComponentUpdate");
        return true;        // 记得要返回true
    }
    componentWillUpdate() {
        alert("componentWillUpdate");
    }
    componentDidUpdate() {
        alert("componentDidUpdate");
    }
    componentWillUnmount() {
        alert("componentWillUnmount");
    }
    render() {
        alert("render");
        return(
            <div>
                <span><h2>{parseInt(this.props.num)}</h2></span>
                <br />
                <span><h2>{this.state.str}</h2></span>
            </div>
        );
    }
}