组件的生命周期: 组件从被创建到挂载到页面中运行,再到组件不用时卸载的过程
生命周期的钩子函数:生命周期的每个阶段调用的一些方法
一、生命周期
1、挂载时(创建阶段)
- 执行时机:组件创建时(由ReactDOM.render()触发---初次渲染)
- 钩子函数的作用:
!不能在render中调用setState
2、更新时
执行时机:setState()、 forceUpdate()、 组件接收到新的props(即父组件render时)
以上三者任意一种变化,就会进入更新阶段,所以有3条路线
路线2:setState() 状态进行了更改时 正常更新组件
shouldComponentUpdate:控制组件更新的“阀门” ——每次要更新前,都会执行该钩子 判断组件是否应该被更新。不写该钩子,会默认返回true
- 自己写了该钩子并返回false,那路线1、2不会从shouldComponentUpdate往下继续执行,所有的状态都不会进行更新,也不会调用render(页面不会刷新)
- 如果写了该钩子,一定要写返回值。否则会报 返回undefined
componentWillUpdate:应该要更新的组件,在将要更新前,调用该钩子
componentDidUpdate:组件更新完时执行
路线3:forceUpdate() 不想对状态进行更改但是又想更新组件时 强制更新
比正常更新少了一个shouldComponentUpdate的环节。
forceUpdate()和setState()一样 必须通过this来调用
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'))
}
//强制更新按钮的回调
force = ()=>{
this.forceUpdate()
}
//组件将要挂载时的钩子(即组件第一次渲染到页面前 执行的函数)
componentWillMount(){
console.log('Count---componentWillMount');
}
//组件挂载完毕后的钩子(组件第一次渲染到页面后 只执行这么一次的函数)
componentDidMount(){
console.log('Count---componentDidMount');
}
//组件将要卸载前的钩子
componentWillUnmount(){
console.log('Count---componentWillUnmount');
}
//控制组件更新的“阀门” (判断组件是否应该被更新)
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>
<button onClick={this.death}>卸载组件</button>
<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
</div>
)
}
}
路线1:父组件重新render,子组件的props变化,触发子组件中的钩子
componentWillReceiveProps:子组件在有接收props的前提下(第一次接收props不调),(后续props变化时)在将要接收新的props前调用
不常用
//父组件A
class A extends React.Component{
//初始化状态
state = {carName:'奔驰'}
changeCar = ()=>{
this.setState({carName:'奥拓'})
}
render(){
return(
<div>
<div>我是A组件</div>
<button onClick={this.changeCar}>换车</button>
<B carName={this.state.carName}/>
</div>
)
}
}
//子组件B
class B extends React.Component{
//组件将要接收新的props前调用的钩子(且它能接到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(
<div>我是B组件,接收到的车是:{this.props.carName}</div>
)
}
}
3、卸载时 componentWillUnmount 常用
-
执行时机:组件从页面中消失前(由ReactDOM.unmountComponentAtNode()触发)
-
作用:一般在这个钩子中做一些收尾的事,例如:清除定时器、取消订阅消息
总结
- 初始化阶段: 由ReactDOM.render()触发---初次渲染
constructor()
componentWillMount() 不常用
render() 第一次渲染时会调用
componentDidMount() 常用:
页面一上来时,做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
- 更新阶段: 由组件内部this.setSate() 或 父组件render 或 强制更新 时触发
- shouldComponentUpdate() 强制更新时没有该步骤
- componentWillUpdate() 不常用
- render() 必写
- componentDidUpdate()
- 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
componentWillUnmount() 常用:
一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
二、新增的钩子
与旧的生命周期相比,废弃了3个will钩子,新增了2个(也不常用,新增的钩子与废弃的钩子功能不同、不是替代关系,根据需要选用)
getDerivedStateFromProps:不能像其他生命周期函数一样给组件实例使用,需要声明为静态方法,且应该返回一个状态对象 或者 null
- 返回状态对象(key跟state中的一样 的对象),会影响到state的更新
- 可以通过参数接收到props、state(state是当前的数据)
- 若需要state的值在任何时候都取决于props(初始化和修改状态都无效),可以使用getDerivedStateFromProps 并返回props(但非必须,在构造器中将接收到的props设为state的初始值也可以实现该需求)
了解即可(尽量不写),因为派生状态会导致代码冗余,使组件难以维护
class Count extends React.Component{
constructor(props){
console.log('Count---constructor');
super(props)
this.state = {count:0}
}
add = ()=>{
const {count} = this.state
this.setState({count:count+1})
}
death = ()=>{
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
force = ()=>{
this.forceUpdate()
}
static getDerivedStateFromProps(props,state){
/*state是当前的数据
适用案例比如:props里的某个值和当前state里的该值进行对比,做不同的判断处理(以哪个值为准)
*/
console.log('getDerivedStateFromProps',props,state);
//return {count:0} 如果返回状态对象,会以状态对象的数据为准(初始化的无效),且该数据无法再更新
//影响更新的原因:getDerivedStateFromProps在生命周期中的位置,处在更新相关的钩子前面
//返回null,正常
return null
//当需要state的值在任何时候都取决于props的时候(初始化和修改状态都无效) 返回props
//所以getDerivedStateFromProps理解成从props里得到派生的状态
// return props
}
//在更新之前获取快照
getSnapshotBeforeUpdate(){
console.log('getSnapshotBeforeUpdate');
return 'atguigu'
}
//组件挂载完毕的钩子
componentDidMount(){
console.log('Count---componentDidMount');
}
//组件将要卸载的钩子
componentWillUnmount(){
console.log('Count---componentWillUnmount');
}
//控制组件更新的“阀门”
shouldComponentUpdate(){
console.log('Count---shouldComponentUpdate');
return true
}
//组件更新完毕的钩子
componentDidUpdate(preProps,preState,snapshotValue){
console.log('Count---componentDidUpdate',preProps,preState,snapshotValue);
}
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>
<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
</div>
)
}
}
//渲染组件
ReactDOM.render(<Count count={199}/>,document.getElementById('test'))
getSnapshotBeforeUpdate: 在更新之前获取快照,必须返回一个快照值 或者 null
-
快照值可以是任意值(包括函数)
-
官网解释:在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)生命周期方法的任何返回值将作为参数,往下传递给
componentDidUpdate()翻译为人话:在render执行后,页面即将出效果的时候调用(在组件马上更新前来个快照,获取一些更新前的一些DOM信息,比如浏览器的宽高之类的)
-
此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。
componentDidUpdate(注意在挂载阶段是不调用该钩子的):
默认能接收到两个参数(本次更新前的props和state)
当getSnapshotBeforeUpdate有返回的快照值时,可以用componentDidUpdate的第三个参数接收
总结
- 初始化阶段: 由ReactDOM.render()触发---初次渲染
- constructor()
- getDerivedStateFromProps
- render()
- componentDidMount()
- 更新阶段: 由组件内部this.setSate() 或 父组件重新render 或 强制更新 触发
- getDerivedStateFromProps
- shouldComponentUpdate() 强制更新没有该钩子
- render()
- getSnapshotBeforeUpdate
- componentDidUpdate()