React 学习笔记 —— 组件生命周期(包含17新版和旧版对比)

生命周期汇总图

生命周期的三个阶段(旧)
1. 初始化阶段: 由ReactDOM.render()触发—初次渲染

  1. constructor()

  2. componentWillMount()

  3. render()

  4. componentDidMount()

2.更新阶段: 由组件内部this.setSate()或父组件重新render触发

  1. shouldComponentUpdate()

  2. componentWillUpdate()

  3. render()

  4. componentDidUpdate()

3.卸载组件: 由ReactDOM.unmountComponentAtNode()触发

  1. componentWillUnmount()

图示如下:

在这里插入图片描述

线路一 初次渲染阶段

在这里插入图片描述

class Demo extends React.Component {
	// 实例化组件时执行
    constructor () {
        super()
        this.state = {
            count: 0
        }
        console.log('constructor')
    }
    handleAdd = () => {
        this.setState({
            count: this.state.count + 1
        })
    }
    handleUnmounted = () => {
        ReactDOM.unmountComponentAtNode(document.getElementById('app'))
    }
    // 将要挂载时执行
    componentWillMount () {
        console.log('componentWillMount')
    }
    // 渲染时执行
    render () {
        console.log('render')
        return (
            <div>
                <div>{this.state.count}</div>
                <button onClick={this.handleAdd}>+1</button>    
                <button onClick={this.handleUnmounted}>卸载</button>    
            </div>
        )
    }
    // 挂载完毕时执行
    componentDidMount () {
        console.log('componentDidMount')
    }
    // 将要卸载时执行
    componentWillUnmount () {
        console.log('componentWillUnmount')
    }
}


ReactDOM.render(<Demo />, document.getElementById('app'))

在这里插入图片描述

线路二 通过修改state

在这里插入图片描述

class Demo extends React.Component {
	constructor () {
		...
	}
	handleAdd = () => {
		...
	}
	handleUnmounted = () => {
		...
	}
	// 返回 true 时,后续的回调函数才有机会执行,相当于控制组件更新的‘阀门’
	shouldComponentUpdate() {
		console.log('shouldComponentUpdate')
		return true
	}
    componentWillMount () {
        console.log('componentWillMount')
    }
    // 组件将要更新时执行
    componentWillUpdate () {
        console.log('componentWillUpdate')
    }
    render () {
		...
    }
    // 组件更新完毕时执行
    componentDidUpdate () {
        console.log('componentDidUpdate')
    }
    componentDidMount () {
        console.log('componentDidMount')
    }
    componentWillUnmount () {
        console.log('componentWillUnmount')
    }
}


ReactDOM.render(<Demo />, document.getElementById('app'))

在这里插入图片描述

线路三 强制更新forceUpdate()

在这里插入图片描述

 class Demo extends React.Component {
     constructor () {
     	...
     }
     handleAdd = () => {
     	...
     }
     handleUnmounted = () => {
		...
     }
     shouldComponentUpdate() {
		...
     }
     componentWillMount () {
         console.log('componentWillMount')
     }
     componentWillUpdate () {
         console.log('componentWillUpdate')
     }
     render () {
         console.log('render')
         return (
             <div>
                 ...
                 // 调用 forceUpdate 强制更新,即 无需调用 setState 也会触发更新
                 <button onClick={()=>this.forceUpdate()}>强制更新</button>    
             </div>
         )
     }
     componentDidUpdate () {
         console.log('componentDidUpdate')
     }
     componentDidMount () {
         console.log('componentDidMount')
     }
     componentWillUnmount () {
         console.log('componentWillUnmount')
     }
 }


 ReactDOM.render(<Demo />, document.getElementById('app'))

在这里插入图片描述

线路四 父组件传给子组件的props发生变化

在这里插入图片描述

class Parent extends React.Component{
    state = {
        count: 0
    }
    handleAdd = () => {
        this.setState({
            count: this.state.count + 1
        })
    }
    // 父组件执行 render
    render () {
        return (
            <div>
            	// 给子组件传递 props
                <Child count={this.state.count}/>
                <button onClick={this.handleAdd}>+1</button>
            </div>
            
        )
    }
}

class Child extends React.Component {
	// 子组件触发 ‘将收到 props 回调’ 
	// 需要注意的是,子组件第一次收到 props 时,不会触发该回调
	// 说起来叫 componentWillReceiveNewProps 或许更为贴切
    componentWillReceiveProps () {
        console.log('componentWillReceiveProps')
    }
    shouldComponentUpdate() {
        console.log('shouldComponentUpdate')
        return true
    }
    componentWillUpdate () {
        console.log('componentWillUpdate')
    }
    render () {
        return (
            <div>
                {this.props.count}
            </div>
        )
    }
    componentDidUpdate () {
        console.log('componentDidUpdate')
    }
}
ReactDOM.render(<Parent />, document.getElementById('app'))

在这里插入图片描述


17版本的生命周期变动

在这里插入图片描述

三个重要的勾子函数

无论在新版还是旧版,这三个钩子函数都没有任何大改动;

  1. render:初始化渲染或更新渲染调用
  2. componentDidMount:开启监听, 发送ajax请求
  3. componentWillUnmount:做一些收尾工作, 如: 清理定时器

即将废用的钩子函数

  • React预计废弃这三个钩子:componentWillReceivePropscomponentWillMountcomponentWillUpdate
  • 在17版本中,这三个待废弃的钩子被重命名为:UNSAFE_componentWillReceivePropsUNSAFE_componentWillMountUNSAFE_componentWillUpdate

现在使用会出现警告,下一个大版本需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用

17版本新增的两个钩子

  • 在17版本中,新增了两个钩子:getDerivedStateFromPropsgetSnapshotBeforeUpdate

getDerivedStateFromProps(props,state)

  • 该方法意为 从props中获取派生的state
  • 该方法为静态方法(static关键字)
  • 该方法接收两个参数,参数1为props、参数2为state
  • 该方法返回null,或者派生的state,页面渲染时,该派生的state 优先级高于 this.state
  • 该方法横跨挂载和更新,可以在任何时候决定用于渲染视图的state
  • 适用场景:该方法用法罕见,仅当需要由props完全决定state时,可能有用
class Demo extends React.Component {
    // 实例化组件时执行
    constructor () {
        super()
        this.state = {
            count: 0
        }
        console.log('constructor')
    }
    handleAdd = () => {
		...
    }
    handleUnmounted = () => {
        ReactDOM.unmountComponentAtNode(document.getElementById('app'))
    }
    static getDerivedStateFromProps (props, state) {
        console.log('getDerivedStateFromProps')
        return null
    }

    // 渲染时执行
    render () {
        console.log('render')
        ...
    }
    // 挂载完毕时执行
    componentDidMount () {
        console.log('componentDidMount')
    }
}

ReactDOM.render(<Demo />, document.getElementById('app'))

在这里插入图片描述

  • 如果返回一个派生的state,那么将以派生的state中所出现的属性为准
 static getDerivedStateFromProps (props, state) {
     console.log('getDerivedStateFromProps')
     return {count: 100}		// 仅修改此处
 }

在这里插入图片描述


getSnapshotBeforeUpdate()

该方法意为在更新之前获取快照
该方法接收两个参数,参数1 prevProps:之前的props;参数2 prevState:之前的state
该方法的返回值,会传递给componentDidMount第三个参数
componentDidMount的三个参数:(prevProps, prevState, returnFromSnapshot)
通过该钩子,可以捕获一些更新前的数据,并传递给componentDidMount
同样是用法罕见的钩子

getSnapshotBeforeUpdate使用场景小demo

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>4_getSnapShotBeforeUpdate的使用场景</title>
	<style>
		.list{
			width: 200px;
			height: 150px;
			background-color: skyblue;
			overflow: auto;
		}
		.news{
			height: 30px;
		}
	</style>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/17.0.1/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/17.0.1/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/17.0.1/babel.min.js"></script>

	<script type="text/babel">
		class NewsList extends React.Component{

			state = {newsArr:[]}

			componentDidMount(){
				setInterval(() => {
					//获取原状态
					const {newsArr} = this.state
					//模拟一条新闻 
					const news = '新闻'+ (newsArr.length+1)
					//更新状态
					this.setState({newsArr:[news,...newsArr]})
				}, 1000);
			}

			getSnapshotBeforeUpdate(){
				return this.refs.list.scrollHeight //此属性是更新前的内容总高度,传给componentDidUpdate的height参数
			}

			componentDidUpdate(preProps,preState,height){
											//    ↓  这个是新的内容总高度
				this.refs.list.scrollTop += this.refs.list.scrollHeight - height
			}

			render(){
				return(
					<div className="list" ref="list">
						{
							this.state.newsArr.map((n,index)=>{
								return <div key={index} className="news">{n}</div>
							})
						}
					</div>
				)
			}
		}
		ReactDOM.render(<NewsList/>,document.getElementById('test'))
	</script>
</body>
</html>
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值