React 组件的生命周期
- React中组件有生命周期,也就是说也有很多钩子函数供我们使用, 组件的生命周期,我们会分为四个阶段,初始化、运行中、销毁、错误处理(16.3之后) ( 共12个钩子函数 )
- 注意: 生命周期钩子函数一定不要写成箭头函数
初始化
在组件初始化阶段会执行 5个钩子函数【 1个将来会使用 】
1. constructor( props )
constructor ( props ) {
/*
作用: 初始化属性 和 定义状态
* 初始化属性: 将父组件绑定在子组件身上的属性获取到 ,
然后 通过super继承给子组件 的 porps属性上
* 定义状态
*/
super( props )
// console.log( props )
// this.props = props
this.state = {
msg: 'Hello World!'
}
console.log('1-constructor')
}
2. static getDerivedStateFromProps(nextProps, prevState) ---- 将来会使用 17.x
static getDerivedStateFromProps(nextProps, prevState) {//(使用之后componentWillMount() 不能用)
console.log(nextProps,prevState)
console.log('getDerivedStateFromProps')
fetch('/data.json')
.then( res => res.json())
.then( data => {
console.log( data ) // 可以数据请求
})
.catch( error => {
if( error ) throw error
})
return { //必须返回一个结果
msg: '你好吗'
}
}
3. componentWillMount() / UNSAFE_componentWillMount()
componentWillMount () {
/*
作用: 组件即将挂载
* 做组件即将挂载的准备工作
* 这个钩子可以进行数据的同步修改
* setState在这个中是可以起作用的
* 16.x 版本使用
* 数据可以获取到
* 真实dom没有拿到
* 类似 vue create + beforeMount
* 数据请求 + 数据修改
* 可能会产生副作用和其他的订阅
1. 副作用: 计时器 、 滚轮事件
项目:
数据请求 + 数据修改
*/
console.log( this.state.msg )
console.log( document.querySelectorAll('h3'))
console.log( document.querySelectorAll('p'))
console.log('2-componentWillMount')
fetch('/data.json')
.then( res => res.json())
.then( data => {
this.setState({
msg: data.name
})
})
.catch( error => {
if( error ) throw error
})
}
UNSAFE_componentWillMount () {
/*
* 这个钩子可以进行数据的同步修改
* setState在这个中是可以起作用的
* 这是旧(16.x之前)的钩子【 不推荐使用 】
*/
this.setState({
msg: '蓝球运动'
})
}
4.render()
render()方法是必需的
render () {
/*
作用:
jsx -> vdom js对象模型
*/
console.log('4-render')
const { msg } = this.state
return (
<Fragment>
<h3> 生命周期 </h3>
<p> { msg } </p>
</Fragment>
)
}
5.componentDidMount()
componentDidMount () {
/*
作用: 组件挂载结束
* 数据拿取到
* 真实dom能不能拿到呢? 能
* 数据请求 + 数据修改
* 真实dom操作 【 第三方库的实例化 】
*/
fetch('/data.json')
.then( res => res.json())
.then( data => {
this.setState({
msg: data.name
})
})
.catch( error => {
if( error ) throw error
})
document.querySelector('h3').style.background = 'red'
console.log( '4-componentDidMount',document.querySelectorAll('h3'))
console.log('4-componentDidMount', document.querySelectorAll('p'))
console.log('4-componentDidMount')
}
运行中( 更新阶段 )
props 或 state 的改变可能会引起组件的更新,组件重新渲染的过程中会调用以下方法
共有7个钩子函数( 4个主要 1个是复用render() 2个将来会使用(17.x) )
1.componentWillReceiveProps() / UNSAFE_componentWillReceiveProps()
componentWillReceiveProps ( nextProps ) {
/*
触发: props改变触发
* nextProps是改变后的值
* this.props.xxx 是改变前的值
作用: 检测项目中的一些变化情况
* React 路由监听
nextProps.xxx === this.props.xxx ? 证明某一个属性( xxx )没有改变
使用场景: 检测到项目中某一个按钮是否触发: 点击注册自动跳转登录
*/
console.log( this.props.name ) // 旧值
console.log('nextProps',nextProps) // nextProps是新值
console.log('props改变触发-componentWillReceiveProps')
}
2.static getDerivedStateFromProps() ----将来会使用(17.x) 复用-初始化中
static getDerivedStateFromProps () {
console.log('getDerivedStateFromProps')
return {
msg: '你好吗'
}
}
3.shouldComponentUpdate() // react性能优化第二方案
shouldComponentUpdate () {
/*
作用: 决定组件是否要更新
必须要有返回值,默认返回值是true
*/
// return true
// return false
console.log('shouldComponentUpdate');
return true;
}
4.componentWillUpdate() / UNSAFE_componentWillUpdate()-- 带有UNSAFE这个的都是旧版本(16.x以前)
componentWillUpdate () {
/*
组件即将更新
为整个更新,做准备工作
类似于vue beforeUpdate
拿到的是更新前的数据 ,可以获得更新后的真实dom
项目中:
这个钩子项目中我们一般不去使用它
问题: 如果我们在这个钩子中使用 setState ,会发生什么?
解答: 会发生死循环
注意: 不要在这个钩子中使用 setState
*/
console.log('this.props.name ',this.props.name)
console.log('真实dom',document.querySelectorAll('p'))
console.log('componentWillUpdate')
}
5.render() 会在更新过程中在执行一次
6.getSnapshotBeforeUpdate() ---- 将来会使用(17.x)
getSnapshotBeforeUpdate () {
// 获得更新前的快照
console.log('getSnapshotBeforeUpdate')
return '组件更新了'
}
7.componentDidUpdate()
componentDidUpdate ( a,b,c ) {
console.log( 'a',a) // 更新前的属性
console.log( 'b',b) // 更新前的状态
console.log( 'c',c) // getSnapshotBeforeUpdate 的返回值
/*
* 组件更新结束
* 可以拿取到更新之后的数据
* 可以获得更新之后的真实DOM
* 项目:
* 操作真实DOM【 第三方库的实例化 】
*/
console.log('this.props.name ',this.props.name)
console.log('真实dom',document.querySelectorAll('p'))
console.log('componentDidUpdate')
}
卸载阶段( 销毁 )
componentWillUnmount()
import React,{ Component,Fragment } from 'react'
import ReactDOM from 'react-dom'
class LifeCircle extends Component{
constructor () {
super()
}
componentWillMount () {
/*
犯错高发地带
*/
this.timer = setInterval(() => {
console.log('hello');
},1000)
}
destory = () => {
/*
React组件内部销毁
* unmountComponentAtNode( Node ) Node是整个项目最大的容器
ReactDOM.unmountComponentAtNode( document.getElementById('root') )
* 这个方法可以删除组件的DOM外壳
不推荐大家使用
*/
ReactDOM.unmountComponentAtNode( document.getElementById('root') )
}
render () {
return (
<Fragment>
<h3> 生命周期 </h3>
<button onClick = { this.destory }> 内部销毁 </button>
</Fragment>
)
}
componentWillUnmount () {
/*
* 组件卸载时触发
* 做善后
* 计时器、滚轮事件‘第三方库实例化出来的实例
*/
clearInterval( this.timer )
console.log('componentWillUnmount')
}
}
export default LifeCircle
错误处理
componentDidCatch() — 16.3版本之后才有的
import React,{ Component,Fragment,logComponentStackToMyService } from 'react'
import ReactDOM from 'react-dom'
import Child from './Child' //这里是引入一个外部子组件
class LifeCircle extends Component{
constructor () {
super()
this.state = {
flag: false
}
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染可以显示降级 UI
console.log('getDerivedStateFromError')
return { flag: true };
}
componentDidCatch(error, info) {
// "组件堆栈" 例子:
// in ComponentThatThrows (created by App)
// in ErrorBoundary (created by App)
// in div (created by App)
// in App
logComponentStackToMyService(info.componentStack);
}
render () {
if( this.state.flag ){
return <h1>Something went wrong.</h1>;
}
return (
<Fragment>
<h3> 生命周期 </h3>
<hr/>
<Child/>
</Fragment>
)
}
}
export default LifeCircle