React 生命周期
React生命周期(生命周期钩子函数)
一个关于生命周期的demo
需求:定义组件实现以下功能:
-
让指定的文本做显示 / 隐藏的渐变动画
-
从完全可见,到彻底消失,耗时2S
-
点击按钮从界面上卸载组件
class Demo extends React.Component{
state = {
opacity:1
}
// 卸载组件
handleComponent = () => {
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
// 组件挂载完毕
componentDidMount(){
this.timer = setInterval(()=>{
let {opacity} = this.state;
opacity -= 0.1
if (opacity <= 0) opacity = 1
this.setState({
opacity:opacity
})
},200)
}
// 组件将要卸载
componentWillUnmount(){
clearInterval(this.timer)
}
// 初始化渲染组件,状态更新之后
render(){
console.log("render")
return (
<div>
<h2 style={{opacity:this.state.opacity}}>react的生命周期</h2>
<button onClick={this.handleComponent}>卸载组件</button>
</div>
)
}
}
// 渲染组件
ReactDOM.render(<Demo />,document.getElementById("test"))
理解
组件从创建到死亡它会经历一些特定的阶段。
React组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用。
我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。
生命周期流程图(旧)
1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
(1)constructor()
constructor()中完成了React数据的初始化,它接受两个参数:props和context,当想在函数内部使用这两个参数时,需使用super()传入这两个参数。
注意:只要使用了constructor()就必须写super(),否则会导致this指向错误。
(2)componentWillMount()
它代表的过程是组件已经经历了constructor()初始化数据后,但是还未渲染DOM时。
(3)render()
render函数会插入jsx生成的dom结构,react会生成一份虚拟dom树,在每一次组件更新时,在此react会通过其diff算法比较更新前后的新旧DOM树,比较以后,找到最小的有差异的DOM节点,并重新渲染。
初始化渲染或更新渲染调用
(4)componentDidMount()
组件第一次渲染完成,此时dom节点已经生成,可以在这里调用ajax请求,返回数据setState后组件会重新渲染。
一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
2.更新阶段: 由组件内部this.setSate()或父组件重新render触发
-
1)setSate更新状态 :shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate
-
2)forceUpdate更新(不更改任何状态中的数据,强制更新一下):componentWillUpdate -> render -> componentDidUpdate
-
3)父组件重新render触发:componentWillReceiveProps -> shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate
componentWillReceiveProps (nextProps)
-
在接受父组件改变后的props需要重新渲染组件时用到的比较多
-
接受一个参数nextProps
-
通过对比nextProps和this.props,将nextProps的state为当前组件的state,从而重新渲染组件
shouldComponentUpdate(nextProps,nextState)
-
主要用于性能优化(部分更新)
-
唯一用于控制组件重新渲染的生命周期,由于在react中,setState以后,state发生变化,组件会进入重新渲染的流程,在这里return false可以阻止组件的更新
-
因为react父组件的重新渲染会导致其所有子组件的重新渲染,这个时候其实我们是不需要所有子组件都跟着重新渲染的,因此需要在子组件的该生命周期中做判断
componentWillUpdate (nextProps,nextState)
shouldComponentUpdate返回true以后,组件进入重新渲染的流程,进入componentWillUpdate
componentDidUpdate(prevProps,prevState)
组件更新完成
3.卸载组件: 由ReactDOM.unmountComponentAtNode()触发
componentWillUnmount()
一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
class Count extends React.Component {
constructor(props){
console.log("Count constructor");
super(props);
// 初始化状态
this.state = {
num: 0
}
}
// 方法
add = () => {
let { num } = this.state;
this.setState({
num: num+1
})
}
//卸载组件按钮的回调
death = ()=>{
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
//强制更新按钮的回调
force = ()=>{
this.forceUpdate()
}
//组件将要挂载的钩子
componentWillMount() {
console.log("Count componentWillMount")
}
// 组件挂载完毕的钩子
componentDidMount() {
console.log("Count componentDidMount")
}
//控制组件更新的“阀门”
shouldComponentUpdate(){
console.log('Count shouldComponentUpdate');
return true
}
// 组件将要更新的钩子
componentWillUpdate(){
console.log('Count componentWillUpdate');
}
// 组件更新完毕的钩子
componentDidUpdate() {
console.log("Count componentDidUpdate")
}
// 初始化渲染组件,状态更新之后
render() {
console.log("Count render")
return (
<div>
<h2>当前求和:{this.state.num}</h2>
<button onClick={this.add}>点我+1</button>
<button onClick={this.death}>卸载组件</button>
<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
</div>
)
}
}
// 渲染组件
ReactDOM.render(<Count />, document.getElementById("test"))
// 父组件render
class A extends React.Component {
state = {
name:"张三"
}
changeName = () => {
this.setState({
name:"李四"
})
}
render(){
return (
<div>
<h2>A组件</h2>
<B name={this.state.name}></B>
<button onClick={this.changeName}>改变名字</button>
</div>
)
}
}
// 子组件
class B extends React.Component {
//组件将要接收新的props的钩子
componentWillReceiveProps(props){
console.log('B---componentWillReceiveProps',props);
}
//控制组件更新的“阀门”
shouldComponentUpdate(){
console.log('B---shouldComponentUpdate');
return true
}
//组件将要更新的钩子
componentWillUpdate(){
console.log('B---componentWillUpdate');
}
//组件更新完毕的钩子
componentDidUpdate(){
console.log('B---componentDidUpdate');
}
render(){
console.log('B---render');
return <h2>B组件:{this.props.name}</h2>
}
}
ReactDOM.render(<A />, document.getElementById("test1"))
生命周期流程图(新)
1、初始化阶段: 由ReactDOM.render()触发---初次渲染
constructor()
getDerivedStateFromProps()
render()
componentDidMount()
2、更新阶段: 由组件内部this.setSate()或父组件重新render触发
getDerivedStateFromProps
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate
getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()。
componentDidUpdate()
卸载组件: 由ReactDOM.unmountComponentAtNode()触发
componentWillUnmount()
即将废弃的勾子
-
componentWillMount
-
componentWillReceiveProps
-
componentWillUpdate
现在使用会出现警告,下一个大版本需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用。