前言 :什么叫做生命周期`
? 首先,我们要知道在拥有许多组件的应用程序中,但组件被销毁时所释放的占用资源是较为重要的。但是要理解什么是生命周期,在这里可以用一个很形象的例子来解释什么叫做生命周期:我们可以将整个生命周期看做“逢年过节所放的鞭炮的引信”,鞭炮从被点燃到燃放完毕可以叫做鞭炮的一生,这里我们所说的组件生命周期也可以理解为----组件从创建到销毁的过程。
? 本文将从以下三点讲解React生命周期:
? (1)新旧生命周期函数的对比与区别
? (2)为什么废弃某些生命周期钩子
? (3)详解新生命周期与实例
1. 生命周期(旧)
生命周期图示
(1)首先先列举React中旧生命周期钩子
挂载时
? 1)constructor
? 2)componentWillMount
? 3)render
? 4)componentDidMount
更新时
? 1)componentWillReceiveProps
? 2)shouldComponentUpdate
? 3)componentWillUpdate
? 4)render
? 5)componentDidUpdate
卸载
? 1)componentWillUnmount
(1-1)挂载时-生命周期钩子详解(顺序就是生命周期钩子执行顺序)
1)constructor
? 在React中,构造器仅用于三种情况:
? (1)通过给this.state赋值对象来初始化内部state。
? (2)给事件处理函数绑定实例
? (3)在构造器中通过this访问props(构造器接收props,传递给super)
class Demo extends React.Component{
constructor(props){
super(props)
this.state = {count:0}
this.change = this.change.bind(this)
}
render(){
return(
<h1 onClick={this.change}>点我</h1>
)
}
}
2)componentWillMount:这是React中不建议的钩子
? 顾名思义:组件将要挂载,在构造器后调用
class Demo extends React.Component{
constructor(props){
super(props)
}
componentWillMount(){
console.log("componentWillMount")
}
render(){
return(
)
}
}
3)render
用于组件实例中,唯一必须实现的方法,用于渲染DOM,render 必须返回ReactDOM
注意 :不要再render使用setState,会触发死循环(比如render里使用setInterval(()={}), time)
class Demo extends React.Component{
render(){
return(
<h1 onClick={this.change}>点我</h1>
)
}
}
4)componentDidMount
组件挂在完毕
class Demo extends React.Component{
constructor(props){
super(props)
}
componentDidMount(){
console.log("componentDidMount")
}
render(){
return(
)
}
}
(1-2)更新时-生命周期钩子(顺序就是生命周期钩子执行顺序)
1)componentWillRecceiveProps:React不建议使用的钩子)
? 组件将要接收props
2)shouldComponentUpdate
? 当props或state发生变化时,shouldComponentUpdate ()会在渲染执行之前被调用。其中携带了一个默认为true得返回值。在setSate使state发生更新时会触发这个钩子函数,forceUpdate (强制更新)在首次渲染或使用时不会调用该方法。
class Demo extends React.Component{
state = {count:0}
change = ()=>{
this.setState({
count: count+1
})
}
shouldComponentUpdate(nextProps, nextState){
console.log("shouldComponentUpdate")
return true
}
force = ()=>{
this.forceUpdate()
}
render(){
return(
<h1 onClick={this.change}>点我</h1>
<h1 onClick={this.force}>forceUpdate</h1>
)
}
}
3)componentWillUpdate
? 组件将要更新(forceUpdate() 会触发这个钩子函数)
4)render
? 用于组件实例中,必须实现的方法
5)componentDidUpdate
? 组件更新完毕
(2-3)在较新版本中被废弃的生命周期钩子
React官方文档给出了以下解释,在17.0版本以上只有在这三个钩子之前加上UNSAFE_才可使用。生命周期添加 “UNSAFE_” 前缀。(这里的 “unsafe” 不是指安全性,而是表示使用这些生命周期的代码在 React 的未来版本中更有可能出现 bug,尤其是在启用异步渲染之后。)
componentWillMount componentWillReceiveProps componentWillUpdate
- 16.3:为不安全的生命周期引入别名,
UNSAFE_componentWillMount 、UNSAFE_componentWillReceiveProps 和 UNSAFE_componentWillUpdate 。(旧的生命周期名称和新的别名都可以在此版本中使用。) - 未来 16.x 版本:为
componentWillMount 、componentWillReceiveProps 和 componentWillUpdate 启用废弃告警。(旧的生命周期名称和新的别名都将在这个版本中工作,但是旧的名称在开发模式下会产生一个警告。) - 17.0:删除
componentWillMount 、componentWillReceiveProps 和 componentWillUpdate 。(在此版本之后,只有新的 “UNSAFE_” 生命周期名称可以使用。)
2. 生命周期(新)
生命周期图示
(2-1)生命周期钩子
挂载时(此时的生命周期钩子将componentWillMount替换掉,其他的不变)
(1)constructor
(2)getDerivedStateFromProps
(3)render
(4)componentDidMount
更新时
(1)New props,setState,forceUpdate都会引起更新
(2) shouldComponentUpdate
(3)render
(4)getSnapshotBeforeUpdate
(5)componentDidUpdate
卸载
(1)componentWillUnmount
(2-2)生命周期钩子详解
(1)constructor与旧生命周期里的构造器无差别
(2)getDerivedStateFromProps
getDerivedStateFromProps 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。
返回值:返回一个对象来更新 state, 如果返回 null 则不更新任何内容
参数: 第一个参数为即将更新的 props, 第二个参数为上一个状态的 state , 可以比较props 和 state来加一些限制条件,防止无用的state更新
注意:getDerivedStateFromProps 是一个静态函数,不能使用this, 也就是只能作一些无副作用的操作
此方法适用于罕见的用例,即 state 的值在任何时候都取决于 props 。
static getDerivedStateFromProps(props, state){}
(3)shouldComponentUpdate同旧生命周期里的钩子(略)
(4)getSnapshotBeforeUpdate
getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate() 。
1)我们这里可以用一个demo来演示其功能:
? 1)动态获取新增数据距离顶部高度
? 2)点击滚动条停留在想查看的位置
2)实现思路
? (1) 循环定时器先动态渲染数据(map)
? (2)回调ref使节点放到Demo实例对象上
? (3)在getSnapshotBeforeUpdate 获取节点距离窗口顶部的高度并将参数height 传给componentDidUpdate ,在componentDidUpdate 计算实时高度
class Demo extends React.Component {
state = {newsArr:[]}
componentDidMount(){
setInterval(()=>{
const {newsArr} = this.state
const news = "didi" + (newsArr.length+1)
this.setState({
newsArr:[news,...newsArr]
})
},1000)
}
listdd = currentNode=>{
this.list = currentNode
console.log(this)
}
getSnapshotBeforeUpdate(){
return this.rootNode.scrollHeight
}
componentDidUpdate(preProps, preState, height){
this.rootNode.scrollTop += this.rootNode.scrollHeight - height
}
render() {
return (
<div className="list" ref={currentNode =>(this.rootNode = currentNode)}>{
this.state.newsArr.map((n, index)=>{
return <div key={index} className="news">{n}</div>
})
}
</div>
)
}
}
ReactDOM.render(<Demo/>,document.getElementById("test"))
(5)componentDidUpdate
? 这个钩子在更新后会被直接调用。首次渲染不会执行此方法。
(5)componentDidUpdate
? 这个钩子在更新后会被直接调用。首次渲染不会执行此方法。
? componentDidUpdate(preProps, preState, sanpshot) 接收三个参数:preProps (之前的props),preState (之前的状态),snapshot (getSnapshotBeforeUpdate里的数据)`
|