react生命周期
-
React中组件有生命周期,也就是说也有很多钩子函数供我们使用, 组件的生命周期,我们会分为四个阶段,初始化、运行中、销毁、错误处理(16.3之后)
生命周期钩子函数一定不要写成箭头函数
1. 初始化阶段
- constructor
- static getDerivedStateFromProps() ---- 将来会使用,
- componentWillMount()
- UNSAFE_componentWillMount() 带有UNSAFE属于过时的钩子函数
- componentWillMount会在17版本之后弃用(使用static getDerivedStateFromProps)
- render()
- componentDidMount()
2.更新阶段
props
或state
的改变可能会引起组件的更新,组件重新渲染的过程中会调用以下方法:
- componentWillReceiveProps()
- static getDerivedStateFromProps()
- shouldComponentUpdate() // react性能优化第二方案
- componentWillUpdate()
- render()
- getSnapshotBeforeUpdate()---- 将来会使用
- componentDidUpdate()
3.卸载阶段
- componentWillUnmount()
4.错误处理
- componentDidCatch() — 16.3版本之后才有的
各生命周期详解
- 初始化阶段
- constructor
- 通过super来继承父类身上传递过来的属性,让后代组件通过this.props接收
- 用来初始化一个状态
- 用来初始化绑定一个方法,将this传递给这个方法
- 注意:不写方法的触发(订阅) 不写具有副作用的代码(比如:定时器)
constructor(props){
super(props) //props接收
this.state = {
msg: 'hello constructor'
} // 初始化状态
this.change = this.change.bind(this)
}
change () {
this.setState({
msg: 'hello slj~~'
})
}
2.componentWillMount
- 提供一次数据修改的机会
- 进行数据请求(axios fetch)
- 注意:虽然可以进行数据请求和初始化数据的修改,但是官方建议我们写在componentDidMount中。(可以减少副作用和订阅)
componentWillMount(){
//数据请求
fetch('./data.json')
.then(res=>res.json())
.then(data=>console.log(data))
.catch(error=>{if(error) throw error});
//修改数据
this.setState({
msg:'睡懒觉'
})
}
3.render
- 计算this.prop this.stare
- 返回一种类型
- react元素 通过jsx创建,既可以是dom元素,也可以是用户自定义的组件。
- 字符串或数字,他们将以文本节点的形式渲染到dom中。
- Portals react16版本中提出的新的解决方案,可以施组件脱离父组件层级直接挂载在DOM树的任何位置。
- null 什么都不渲染
- 布尔值 是什么都不渲染
- render()方法必须是一个纯函数,他不应该改变state,也不能直接和浏览器进行交互,应该将事件放在其他生命周期函数中。
- 如果shouldComponentUpdate()返回false,render()不会被调用
- jsx->vdom 对象
render(){
return (
<Fragment>
<h3>Father组件</h3>
<button onClick={this.change}>点击</button>
<p>constructor: { this.state.msg}</p>
</Fragment>
)
}
4.componentDidMount(组件挂载结束)
- 数据请求
- 数据修改
- 将render函数生成的vdom对象渲染成真实dom,然后挂载在id为root的容器中
- 如果要初始化第三方的dom库,也在这里进行初始化。只有到这里才能获取到真实的dom.
- 通常在这里进行ajax请求
componentDidMount(){
fetch('./data.json')
.then(res=>res.json())
.then(data=>{console.log('componentDidMount');
this.setstate({
msg:data.name
})
})
.catch(if(error)=>console.log(error))
}
5.getDerivedStateFromProps
- 数据请求
- 数据修改
- 返回值就是修改后的数据
- 函数之前加一个static
static getDerivedStateFromProps(nextProps,provState){
console.log(nextProps);//将来的属性
console.log(provState);//变化前的值
return{
msg:'请求啊'
}
}
- 更新阶段
- compomentWillReciveProps
- 触发: 属性发生改变,就会触发
- 这个钩子函数一定能监听到整个当前组件的属性变化—>当前组件的路由也可以监听到
- 应用场景 1.路由监听
componentWillReceiveProps(nextProps){
console.log('componentWillReceiveProps');
console.log(nextProps);//属性变化之后的值
}
2.shouldComponentUpdate(组件即将更新生成新的Vdom)
- 决定组件是否更新
- 返回值true ,更新
- 返回值false ,不更新
- 这个钩子函数是React性能优化的关键钩子
shouldComponentUpdate(){
}
3.compomentDidUpdate(组件更新结束)
- 数据请求
- DOM操作(第三方库的实例化)
- 接受 getSnapshotBeforeUpdate() 第三个参数作为返回值
- 使用fiber算法进行新vdom和旧vdom对比,生成新的patch对象在根据patch对象进行页面渲染
componentDidUpdate ( ) {
fetch( '/data.json' )
.then( res => res.json())
.then( data => console.log( 'componentDidUpdate',data ))
.catch( error => {
if( error ) console.log( error )
})
document.querySelector('h3').style.background = 'red'
console.log( 'componentDidUpdate' )
}
}
- 卸载阶段
- componentWillUnmount
- 组件外部销毁:开关【推荐】
- 组件内部销毁:ReactDOM.unmountComponentAtNode( document.querySelector(’#root’) ) //必须是root
destory = () => {
ReactDOM.unmountComponentAtNode( document.querySelector('#root') ) //必须是root
}
render () {
return (
<Fragment>
<div className = "father-box">
<h3> Father组件 - 更新阶段</h3>
<button onClick = { this.destory }> 内部销毁 </button>
<p> constructor : { this.state.msg } </p>
<p> money: { this.props.money } </p>
</div>
</Fragment>
)
}
- 错误处理
- componentDidCatch(error, info)