(react基础)类组件的生命周期

182 阅读6分钟

组件的生命周期: 组件从被创建到挂载到页面中运行,再到组件不用时卸载的过程

生命周期的钩子函数:生命周期的每个阶段调用的一些方法

一、生命周期

生命周期(旧.jpg

1、挂载时(创建阶段)

  • 执行时机:组件创建时(由ReactDOM.render()触发---初次渲染)
  • 钩子函数的作用: 创建时-函数的作用.png !不能在render中调用setState

2、更新时

执行时机:setState()、 forceUpdate()、 组件接收到新的props(即父组件render时)

以上三者任意一种变化,就会进入更新阶段,所以有3条路线

路线2:setState() 状态进行了更改时 正常更新组件

shouldComponentUpdate:控制组件更新的“阀门” ——每次要更新前,都会执行该钩子 判断组件是否应该被更新。不写该钩子,会默认返回true

  • 自己写了该钩子并返回false,那路线1、2不会从shouldComponentUpdate往下继续执行,所有的状态都不会进行更新,也不会调用render(页面不会刷新)
  • 如果写了该钩子,一定要写返回值。否则会报 返回undefined

componentWillUpdate:应该要更新的组件,在将要更新前,调用该钩子

componentDidUpdate:组件更新完时执行

路线3:forceUpdate() 不想对状态进行更改但是又想更新组件时 强制更新

比正常更新少了一个shouldComponentUpdate的环节。

forceUpdate()和setState()一样 必须通过this来调用

class Count extends React.Component{
    //构造器
    constructor(props){
        console.log('Count---constructor');
        super(props)
        //初始化状态
        this.state = {count:0}
    }

    //加1按钮的回调
    add = ()=>{
        //获取原状态
        const {count} = this.state
        //更新状态
        this.setState({count:count+1})
    }

    //卸载组件按钮的回调
    death = ()=>{
        ReactDOM.unmountComponentAtNode(document.getElementById('test'))
    }

    //强制更新按钮的回调
    force = ()=>{
        this.forceUpdate()
    }

    //组件将要挂载时的钩子(即组件第一次渲染到页面前 执行的函数)
    componentWillMount(){
        console.log('Count---componentWillMount');
    }

    //组件挂载完毕后的钩子(组件第一次渲染到页面后 只执行这么一次的函数)
    componentDidMount(){
        console.log('Count---componentDidMount');
    }

    //组件将要卸载前的钩子
    componentWillUnmount(){
        console.log('Count---componentWillUnmount');
    }

    //控制组件更新的“阀门” (判断组件是否应该被更新)
    shouldComponentUpdate(){
        console.log('Count---shouldComponentUpdate');
        return true
    }

    //组件将要更新的钩子(更新前调用)
    componentWillUpdate(){
        console.log('Count---componentWillUpdate');
    }

    //组件更新完毕的钩子
    componentDidUpdate(){
        console.log('Count---componentDidUpdate');
    }

    render(){
        console.log('Count---render');
        const {count} = this.state
        return(
            <div>
                <h2>当前求和为:{count}</h2>
                <button onClick={this.add}>点我+1</button>
                <button onClick={this.death}>卸载组件</button>
                <button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
            </div>
        )
    }
}

路线1:父组件重新render,子组件的props变化,触发子组件中的钩子

componentWillReceiveProps:子组件在有接收props的前提下(第一次接收props不调),(后续props变化时)在将要接收新的props前调用

不常用

//父组件A
class A extends React.Component{
    //初始化状态
    state = {carName:'奔驰'}

    changeCar = ()=>{
        this.setState({carName:'奥拓'})
    }

    render(){
        return(
            <div>
                <div>我是A组件</div>
                <button onClick={this.changeCar}>换车</button>
                <B carName={this.state.carName}/>
            </div>
        )
    }
}

//子组件B
class B extends React.Component{
    //组件将要接收新的props前调用的钩子(且它能接到props)
    componentWillReceiveProps(props){
        console.log('B---componentWillReceiveProps',props);
    }

    shouldComponentUpdate(){
        console.log('B---shouldComponentUpdate');
        return true
    }
    componentWillUpdate(){
        console.log('B---componentWillUpdate');
    }

    componentDidUpdate(){
        console.log('B---componentDidUpdate');
    }

    render(){
        console.log('B---render');
        return(
            <div>我是B组件,接收到的车是:{this.props.carName}</div>
        )
    }
}

3、卸载时 componentWillUnmount 常用

  • 执行时机:组件从页面中消失前(由ReactDOM.unmountComponentAtNode()触发)

  • 作用:一般在这个钩子中做一些收尾的事,例如:清除定时器、取消订阅消息

总结

  1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
  1. constructor()

  2. componentWillMount() 不常用

  3. render() 第一次渲染时会调用

  4. componentDidMount() 常用:

    页面一上来时,做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息

  1. 更新阶段: 由组件内部this.setSate() 或 父组件render 或 强制更新 时触发
  1. shouldComponentUpdate() 强制更新时没有该步骤
  2. componentWillUpdate() 不常用
  3. render() 必写
  4. componentDidUpdate()
  1. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发

componentWillUnmount() 常用:

一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

二、新增的钩子

与旧的生命周期相比,废弃了3个will钩子,新增了2个(也不常用,新增的钩子与废弃的钩子功能不同、不是替代关系,根据需要选用

生命周期(新).jpg

getDerivedStateFromProps:不能像其他生命周期函数一样给组件实例使用,需要声明为静态方法,且应该返回一个状态对象 或者 null

  • 返回状态对象(key跟state中的一样 的对象),会影响到state的更新
  • 可以通过参数接收到props、state(state是当前的数据)
  • 若需要state的值在任何时候都取决于props(初始化和修改状态都无效),可以使用getDerivedStateFromProps 并返回props(但非必须,在构造器中将接收到的props设为state的初始值也可以实现该需求

了解即可(尽量不写),因为派生状态会导致代码冗余,使组件难以维护

class Count extends React.Component{
	constructor(props){
		console.log('Count---constructor');
		super(props)
		this.state = {count:0}
	}
	add = ()=>{
		const {count} = this.state
		this.setState({count:count+1})
	}
	death = ()=>{
		ReactDOM.unmountComponentAtNode(document.getElementById('test'))
	}
	force = ()=>{
		this.forceUpdate()
	}
	static getDerivedStateFromProps(props,state){
		/*state是当前的数据
                适用案例比如:props里的某个值和当前state里的该值进行对比,做不同的判断处理(以哪个值为准)
		*/
		console.log('getDerivedStateFromProps',props,state);

		//return {count:0} 如果返回状态对象,会以状态对象的数据为准(初始化的无效),且该数据无法再更新
		//影响更新的原因:getDerivedStateFromProps在生命周期中的位置,处在更新相关的钩子前面

		//返回null,正常
		return null

		//当需要state的值在任何时候都取决于props的时候(初始化和修改状态都无效) 返回props
		//所以getDerivedStateFromProps理解成从props里得到派生的状态
		// return props
	}

	//在更新之前获取快照
	getSnapshotBeforeUpdate(){
		console.log('getSnapshotBeforeUpdate');
		return 'atguigu'
	}

	//组件挂载完毕的钩子
	componentDidMount(){
		console.log('Count---componentDidMount');
	}

	//组件将要卸载的钩子
	componentWillUnmount(){
		console.log('Count---componentWillUnmount');
	}

	//控制组件更新的“阀门”
	shouldComponentUpdate(){
		console.log('Count---shouldComponentUpdate');
		return true
	}

	//组件更新完毕的钩子
	componentDidUpdate(preProps,preState,snapshotValue){
		console.log('Count---componentDidUpdate',preProps,preState,snapshotValue);
	}
	
	render(){
		console.log('Count---render');
		const {count} = this.state
		return(
			<div>
				<h2>当前求和为:{count}</h2>
				<button onClick={this.add}>点我+1</button>
				<button onClick={this.death}>卸载组件</button>
				<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
			</div>
		)
	}
}

//渲染组件
ReactDOM.render(<Count count={199}/>,document.getElementById('test'))

getSnapshotBeforeUpdate: 在更新之前获取快照,必须返回一个快照值 或者 null

  • 快照值可以是任意值(包括函数)

  • 官网解释:在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)生命周期方法的任何返回值将作为参数,往下传递给componentDidUpdate()

    翻译为人话:在render执行后,页面即将出效果的时候调用(在组件马上更新前来个快照,获取一些更新前的一些DOM信息,比如浏览器的宽高之类的)

  • 此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。

componentDidUpdate(注意在挂载阶段是不调用该钩子的):

  • 默认能接收到两个参数(本次更新前的props和state)

  • 当getSnapshotBeforeUpdate有返回的快照值时,可以用componentDidUpdate的第三个参数接收

总结

  1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
    1. constructor()
    2. getDerivedStateFromProps
    3. render()
    4. componentDidMount()
  2. 更新阶段: 由组件内部this.setSate() 或 父组件重新render 或 强制更新 触发
    1. getDerivedStateFromProps
    2. shouldComponentUpdate() 强制更新没有该钩子
    3. render()
    4. getSnapshotBeforeUpdate
    5. componentDidUpdate()