React----组件生命周期知识点整理

x33g5p2x  于2021-09-26 转载在 React  
字(8.0k)|赞(0)|评价(0)|浏览(369)

案例引入

需求:定义组件实现以下功能:

让指定的文本做显示 / 隐藏的渐变动画
1.
从完全可见,到彻底消失,耗时2S
1.
点击“不活了”按钮从界面中卸载组件

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Hello_React</title>
	</head>
	<body>
		<!-- 准备好一个容器 -->
		<div id="showInterval"></div>
		
	<!-- 引入react核心库 -->	
		<script type="text/javascript" src="./js/react.development.js"></script>
	 <!-- 引入react-dom,用于支持react操作dom -->
	 <script type="text/javascript" src="./js/react-dom.development.js"></script>
	  <!-- 引入babel,用于将jsx转换为js -->
	 	 <script type="text/javascript" src="./js/babel.min.js"></script>
	 <!-- 引入prop-types,用于对组件标签属性进行限制 -->
	  <script type="text/javascript" src="./js/prop-types.js"></script>
	 <script type="text/babel">
//创建组件
//生命周期函数,生命周期钩子函数
class Life extends React.Component
{
	state={opacity:1}
	

	//组件挂载完毕
	componentDidMount()
	{
		//给类实例增加一个timer属性,保存当前定时器的唯一标识
		this.timer=setInterval(()=>{
			//获取原状态
			let {opacity}=this.state
			//减小0.1
			opacity-=0.1
			if(opacity<=0) opacity=1
			//设置新的透明度
			this.setState({opacity})
		},200)
	}
	
	//组件即将卸载
	componentWillUnmount()
	{
		//清除定义器
		clearInterval(this.timer)
	}
	//卸载组件
	death=()=>
	{
		ReactDOM.unmountComponentAtNode(document.getElementById('showInterval'));
	}
	
	render()
	{
		return(
		<div>
		<h2 style={{opacity:this.state.opacity}}>React学不会怎么办? </h2>
		<button onClick={this.death}>拜拜了</button>
		</div>
		)
	}
	
}
//渲染组件
ReactDOM.render(<Life/>,document.getElementById('showInterval'))

	 </script>
	</body>
</html>

js使用字面量创建对象,当属性名和属性值同名时,可简写{name},等同于{name:name}

注意:

区分类组件中自定义方法,而React会在创建完类实例后,通过类实例调用的方法

如果是自定义方法,React不会自己去调用,因此一般使用变量+箭头函数的形式,将该自定义方法作为一个事件的触发函数

生命周期理解

1.组件从创建到死亡它会经历一些特定的阶段。
2.React组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用。
3.我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。

生命周期流程图(旧)

对于shouldComponentUpdate是否应该更新组件的方法来说,如果我们不重写父类该方法,那么该方法默认返回true,重写该方法,返回false,那么下面的流程就不会走了

父子组件

在A的类组件的render方法中调用B组件的标签,此时A是父组件,B是子组件

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>
		)
	}
}
class B extends React.Component
{
	render(){
		return(
		<div>
		<div>B组件</div>
		 <div>接收到的车是:{this.props.carName}</div>
		</div>
		)
	}
}
//渲染组件
ReactDOM.render(<A/>,document.getElementById('showInterval'))

componentWillReceiveProps方法—第一次挂载时不会调用,后面更新时才会调用

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>
		)
	}
}
class B extends React.Component
{
	//组件将要接收新的
	componentWillReceiveProps(props)
	{
		console.log(props)
	}
	shouldComponentUpdate()
	{
		console.log('shouldComponentUpdate')
		return true
	}
	componentWillUpdate()
	{
		console.log('componentWillUpdate')
	}
	componentDidUpdate()
	{
		console.log('conponentDidUpdate')
	}
	render(){
		console.log('render')
		return(
		<div>
		<div>B组件</div>
		 <div>接收到的车是:{this.props.carName}</div>
		</div>
		)
	}
}
//渲染组件
ReactDOM.render(<A/>,document.getElementById('showInterval'))

旧版生命周期总结

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(),一般在这个钩子中做一些收尾的事情,例如:关闭定时器,取消订阅消息

React生命周期----新版本

新版本的React即将废弃三个钩子,如果还要使用前面加上UNSAFE_,尽量少用

新增钩子getDerivedStateFromProps ----让组件在 props 变化时更新 state

static getDerivedStateFromProps(props, state)

getDerivedStateFromProps 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。

如果返回的不是一个js对象,那么效果等同于null

此方法适用于罕见的用例,即 state 的值在任何时候都取决于 props

getDerivedStateFromProps 的存在只有一个目的:让组件在 props 变化时更新 state。

class B extends React.Component
{
	state={count:520}
   static getDerivedStateFromProps(props,state)
   {
	   console.log(props,state)
	   if(props.count===state.count)
        return state
		return props
   }
	render(){
		console.log('render')
		return(
		<div>
		<div>count的值为: {this.state.count}</div>
		</div>
		)
	}
}
//渲染组件
ReactDOM.render(<B count={521}/>,document.getElementById('showInterval'))

一旦getDerivedStateFromProps返回一个js对象,那么后面state的值在任何时候都为该js对象的值,即使调用setState的方法,也没有效果

新增钩子getSnapshotBeforeUpdate----保留渲染前的一些信息

getSnapshotBeforeUpdate(prevProps, prevState)

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

应返回 snapshot 的值(或 null)

class B extends React.Component
{
	state={count:520}
	//组件在 props 变化时更新 state
   static getDerivedStateFromProps(props,state)
   {
	   console.log('getDerivedStateFromProps')
    return null
   }
   //应该更新吗
   shouldComponentUpdate()
   {
	   console.log('shouldComponentUpdate')
	   return true
   }
   //更新前获取快照
   getSnapshotBeforeUpdate(prevProps, prevState)
   {
	   console.log('getSnapshotBeforeUpdate')
	   return null
   }
   //更新完毕
   componentDidUpdate(prevProps, prevState, snapshot)
   {
	   console.log('componentDidUpdate: ',prevProps, prevState, snapshot)
    }
	add=()=>{this.setState({count:this.state.count+1})}
	render(){
		console.log('render')
		return(
		<div>
		<div>count的值为: {this.state.count}</div>
		<button onClick={this.add}>加一</button>
		</div>
		)
	}
}
//渲染组件
ReactDOM.render(<B count={521}/>,document.getElementById('showInterval'))

getSnapshotBeforeUpdate的应用案例—滚动条

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Hello_React</title>
<style>
.list
{
	width:200px;
	height:150px;
	background-color:skyblue;
	overflow: auto;
}
.news
{
	height: 30px;
}
</style>		
	</head>
	<body>
		<!-- 准备好一个容器 -->
		<div id="show"></div>
		
		<script type="text/javascript" src="./js/react.development.js"></script>
	 <script type="text/javascript" src="./js/react-dom.development.js"></script>
	 	 <script type="text/javascript" src="./js/babel.min.js"></script>
	  <script type="text/javascript" src="./js/prop-types.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(prevProps, prevState)
	{
		//返回更新前的滚动条高度
		return this.refs.list.scrollHeight
	}
	//确保滑到某个位置,当前数据不会被挤下去
	//更新后的数据
	componentDidUpdate(prevProps, prevState, height)
	{
		//height获得的是getSnapshotBeforeUpdate的返回值
		//this.refs.list.scrollHeight-height等于30,即一条新闻的高度
		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('show'))
	 </script>
	</body>
</html>

scrollTop和scrollHeight

scrollTop: 代表在有滚动条时,滚动条向下滚动的距离也就是元素顶部被遮住部分的高度。在没有滚动条时scrollTop==0恒成立。单位px,可读可设置。

scrollHeight: 因为子元素比父元素高,父元素不想被子元素撑的一样高就显示出了滚动条,在滚动的过程中本元素有部分被隐藏了,scrollHeight代表包括当前不可见部分的元素的高度。而可见部分的高度其实就是clientHeight,也就是scrollHeight>=clientHeight恒成立。在有滚动条时讨论scrollHeight才有意义,在没有滚动条时scrollHeight==clientHeight恒成立。单位px,只读元素。

搞清clientHeight、offsetHeight、scrollHeight、offsetTop、scrollTop

总结

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()

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

1.componentWillUnmount()

重要的勾子

1.render:初始化渲染或更新渲染调用

2.componentDidMount:开启监听, 发送ajax请求

3.componentWillUnmount:做一些收尾工作, 如: 清理定时器

即将废弃的勾子

1.componentWillMount

2.componentWillReceiveProps

3.componentWillUpdate

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

相关文章