知识总结 React【生命周期】

182 阅读5分钟

生命周期

前置知识

高阶函数

如果一个函数符合下面两个规范中的任何一个,那就称为高阶函数。

  1. 若A函数接收的参数是一个函数,那么A就可以称之为高阶函数。
  2. 若A函数调用的返回值是一个函数,那么A就可以称之为高阶函数。

函数柯里化

通过函数调用继续返回函数的形式,实现多次接收参数最后统一处理的函数编码格式。

class Demo extends React.Component {
  saveInput = (type) => {
    console.log(type); // username
    return (event) => {
      this.setState({[type]: event.target.value})
    }
  }
  render() {
    return (
      <input onChange={this.saveInput('username')} type="text" />
    )
  }
}

react 中事件需要传递一个函数过去,传参加括号后会导致函数立即执行,因此利用高阶函数返回一个箭头函数给事件 onChange ,调用该事件的实际上就是调用 return 的箭头函数。

旧版本

react生命周期(旧).png

初始化阶段

组件挂载时,会触发四个生命周期函数,分别是:

  1. constructor构造器。
  2. componentWillMount组件将要挂载。
  3. render 组件挂载。
  4. componentDidMount 组件挂载完毕。 这个组件常用,一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息。
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'))
	}

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

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

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

	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>
			</div>
		)
	}
}	
		
//渲染组件
ReactDOM.render(<Count/>,document.getElementById('test'))

最终运行结果如下:

image.png

更新阶段

正常更新

由组件内部 this.setSate() 或父组件 render 触发,更新 state 内的数据触发的更新叫做正常更新。

  1. shouldComponentUpdate() 更新前阀门,不设置默认返回 true ,设置这个钩子函数就必须返回一个布尔值。为假则不执行后续操作不更新。
  2. componentWillUpdate() 组件更新前。
  3. render() =====> 必须使用的一个
  4. componentDidUpdate() 组件更新完毕。
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})
	}


	//控制组件更新的“阀门”
	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>
			</div>
		)
	}
}

最终运行结果如下:

image.png

强制更新

不想对状态 state 做出修改而触发的更新叫做强制更新。

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

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

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

	render(){
		console.log('Count---render');
		const {count} = this.state
		return(
			<div>
				<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
			</div>
		)
	}
}

最终结果如下图所示:

image.png

卸载组件

ReactDOM.unmountComponentAtNode() 触发。

componentWillUnmount() =====> 常用, 一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息。

父组件render流程

新版本

react生命周期(新).png

创建阶段(一次)

执行时机:组件创建时(页面加载时)

执行顺序:

钩子函数触发时机作用
constructor创建组件时,最先执行1. 初始化 state 2. 创建Ref等
getDerivedStateFromProps每次组件渲染都会触发1. 该函数不是实例上的方法,需要加 static 2. 需要返回一个对象,或者null
render每次组件渲染都会触发渲染UI
componentDidMount组件挂载(完成DOM渲染)后1. 发送网络请求 2.DOM操作

总结:

  1. constructor 对标 Vue中的 beforeCreate/created
  2. componentDidMount 对标 Vue中的 Mounted
  3. 在一个完整的生命周期中,constructorcomponentDidMount 只会执行一次。
  4. 在一个完整的生命周期中,render 会执行多次。
  5. getDerivedStateFromProps(props, state) 有两个参数,返回 null 正常执行,返回对象中有 state 内的 key 属性时,会替换掉初始化的值,并无法更改。

注意:

  1. 在React中,我们在componentDidMount 中发请求,绝对不在constructor 中发请求。
  2. getDerivedStateFromProps(props, state) 适用于罕见的案例,即 state 的值在任何时候都取决于 props 的值。

更新阶段(多次)

  • 执行时机:

    1. setState()
    2. 组件接收到新的 props
  • 说明:以上三者任意一种变化,组件就会重新渲染

  • 执行顺序

钩子函数触发时机作用
render每次组件渲染都会触发渲染UI(与 挂载阶段 是同一个render)(注意: 不能调用setState()
componentDidUpdate数据更新-组件更新DOM操作,可以获取到更新后的DOM内容,不要调用setState
getSnapshotBeforeUpdate数据更新前-组件更新前组件更新之前获取到DOM的信息

总结:

  1. 触发组件更新的方式(常用),两种:

    1. props 值的改变
    2. setState() 改变 state
  2. 更新阶段触发的钩子函数,有两个

    1. render
    2. componentDidUpdate
  3. rendercomponentsDidUpdate 都可以拿到更新后的值。

  4. rendercomponentsDidUpdate 中都不能调用setState ,会造成死循环。

注意:

  1. 不论DOM中有没有使用数据,钩子函数都会被触发。(与vue不同)
  2. react中的更新,指的是数据更新,而非视图更新。(与vue不同)

卸载阶段(一次)

  • 执行时机:组件从页面中消失
钩子函数触发时机作用
unmountComponentAtNode组件卸载(从页面中消失)卸载组件
componentWillUnmount组件将要卸载执行清理工作(比如:清理定时器等)

新旧版本对比

  1. 废弃三个钩子:生命周期函数 componentWillMountcomponentWillReceivePropscomponentWillUpdate 这三个已经改名了,需要在前面加上 UNSAVE_ 。(记忆法:三个有 will 相关的钩子函数都加上 UNSAVE_ 前缀)官方文档上说明,这些生命周期代码在未来版本中可能会出bug,因此现在停用。
  2. 提出两个钩子:getDerivedStateFromPropsgetSnapishotBeforeUpdate 钩子。用法罕见。

总结

重要的勾子

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