生命周期
前置知识
高阶函数
如果一个函数符合下面两个规范中的任何一个,那就称为高阶函数。
- 若A函数接收的参数是一个函数,那么A就可以称之为高阶函数。
- 若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
的箭头函数。
旧版本
初始化阶段
组件挂载时,会触发四个生命周期函数,分别是:
constructor
构造器。componentWillMount
组件将要挂载。render
组件挂载。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'))
最终运行结果如下:
更新阶段
正常更新
由组件内部 this.setSate()
或父组件 render
触发,更新 state
内的数据触发的更新叫做正常更新。
shouldComponentUpdate()
更新前阀门,不设置默认返回true
,设置这个钩子函数就必须返回一个布尔值。为假则不执行后续操作不更新。componentWillUpdate()
组件更新前。render()
=====> 必须使用的一个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>
)
}
}
最终运行结果如下:
强制更新
不想对状态 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>
)
}
}
最终结果如下图所示:
卸载组件
由 ReactDOM.unmountComponentAtNode()
触发。
componentWillUnmount()
=====> 常用,
一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息。
父组件render流程
新版本
创建阶段(一次)
执行时机:组件创建时(页面加载时)
执行顺序:
钩子函数 | 触发时机 | 作用 |
---|---|---|
constructor | 创建组件时,最先执行 | 1. 初始化 state 2. 创建Ref等 |
getDerivedStateFromProps | 每次组件渲染都会触发 | 1. 该函数不是实例上的方法,需要加 static 2. 需要返回一个对象,或者null |
render | 每次组件渲染都会触发 | 渲染UI |
componentDidMount | 组件挂载(完成DOM渲染)后 | 1. 发送网络请求 2.DOM操作 |
总结:
constructor
对标 Vue中的beforeCreate/created
。componentDidMount
对标 Vue中的Mounted
。- 在一个完整的生命周期中,
constructor
与componentDidMount
只会执行一次。- 在一个完整的生命周期中,
render
会执行多次。getDerivedStateFromProps(props, state)
有两个参数,返回null
正常执行,返回对象中有state
内的key
属性时,会替换掉初始化的值,并无法更改。
注意:
- 在React中,我们在
componentDidMount
中发请求,绝对不在constructor
中发请求。getDerivedStateFromProps(props, state)
适用于罕见的案例,即state
的值在任何时候都取决于props
的值。
更新阶段(多次)
-
执行时机:
setState()
- 组件接收到新的
props
-
说明:以上三者任意一种变化,组件就会重新渲染
-
执行顺序
钩子函数 | 触发时机 | 作用 |
---|---|---|
render | 每次组件渲染都会触发 | 渲染UI(与 挂载阶段 是同一个render)(注意: 不能调用setState() ) |
componentDidUpdate | 数据更新-组件更新 | DOM操作,可以获取到更新后的DOM内容,不要调用setState |
getSnapshotBeforeUpdate | 数据更新前-组件更新前 | 组件更新之前获取到DOM的信息 |
总结:
触发组件更新的方式(常用),两种:
props
值的改变setState()
改变state
更新阶段触发的钩子函数,有两个
render
componentDidUpdate
render
与componentsDidUpdate
都可以拿到更新后的值。
render
与componentsDidUpdate
中都不能调用setState
,会造成死循环。
注意:
- 不论DOM中有没有使用数据,钩子函数都会被触发。(与vue不同)
- react中的更新,指的是数据更新,而非视图更新。(与vue不同)
卸载阶段(一次)
- 执行时机:组件从页面中消失
钩子函数 | 触发时机 | 作用 |
---|---|---|
unmountComponentAtNode | 组件卸载(从页面中消失) | 卸载组件 |
componentWillUnmount | 组件将要卸载 | 执行清理工作(比如:清理定时器等) |
新旧版本对比
- 废弃三个钩子:生命周期函数
componentWillMount
、componentWillReceiveProps
和componentWillUpdate
这三个已经改名了,需要在前面加上UNSAVE_
。(记忆法:三个有will
相关的钩子函数都加上UNSAVE_
前缀)官方文档上说明,这些生命周期代码在未来版本中可能会出bug,因此现在停用。 - 提出两个钩子:
getDerivedStateFromProps
和getSnapishotBeforeUpdate
钩子。用法罕见。
总结
重要的勾子
render
:初始化渲染或更新渲染调用componentDidMount
:开启监听, 发送ajax请求componentWillUnmount
:做一些收尾工作, 如: 清理定时器