(旧)
组件从创建到死亡,会经过一些特定的阶段
React组件中包含一系列钩子函数{生命周期回调函数},会在特定的时刻调用
我们在定义组件的时候,会在特定的声明周期回调函数中,做特定的工作
如下图是旧生命周期的结构图:
我们通过一个案例更详细的了解这个生命周期:
class A extends React.Component{
constructor(props){
console.log("A --- constructor")
super(props);
this.state = {num:1}
}
add = () => {
let {num} = this.state;
this.setState({num:num+1});
//强制更新
//this.forceUpdate();
}
render(){
console.log("A --- render");
return (
<div>
<h1>这个是第{this.state.num}个</h1>
<B name = {this.state.num}/>
<button onClick = {this.add}>点击加一</button>
</div>
)
}
//在render之前执行
componentWillMount(){
console.log("A --- componentWillMount");
}
//在render之后执行
componentDidMount(){
console.log("A --- componenetDidMount");
}
//更新操作 setState之后执行,判断是否可以更新(true可以,false不可以)
shouldComponentUpdate(){
console.log("A --- shouldComponentUpdate");
return true;
}
// 组件将要更新之前
componentWillUpdate(){
console.log("A --- componentWillUpdate");
}
//组件更新之后,该函数可以接受相应的参数
componentDidUpdate(){
console.log("A --- componentDidUpdate");
}
//卸载组件之后
componentWillUnmonut(){
console.log("A --- componentWillUnmonut");
}
}
class B extends React.Component{
render(){
return(
<div>
<h1>这个是B组件,传递过来的是:{this.props.name}</h1>
</div>
)
}
//父组件进行了更新,子组件先执行这个【注意,第一次传递数据的时候,并不执行】
componentWillReceiveProps(){
console.log("A --- componentWillReceiveProps");
}
}
ReactDOM.render(<A />,document.getElementById("div"));
我们在控制台看一下:
当我们刚刚打开控制台的时候,组件第一次加载:
当我们点击按钮更新sate的时候:
(新)
在最新的react版本中,有些生命周期钩子被抛弃了,在官网中是这样说的:
我们得到最重要的经验是,过时的组件生命周期往往会带来不安全的编码实践,具体函数如下:
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
这些生命周期方法经常被误解和滥用;此外,我们预计,在异步渲染中,它们潜在的误用问题可能更大。我们将在即将发布的版本中为这些生命周期添加 “UNSAFE_” 前缀。(这里的 “unsafe” 不是指安全性,而是表示使用这些生命周期的代码在 React 的未来版本中更有可能出现 bug,尤其是在启用异步渲染之后。)
由此可见,新版本中并不推荐持有这三个函数,取而代之的是带有UNSAFE_ 前缀的三个函数,比如: UNSAFE_ componentWillMount。即便如此,其实React官方还是不推荐大家去使用,在以后版本中有可能会去除这几个函数。
如下图是新的生命周期:
从图上可以看出,新生命周期和旧生命周期的区别主要有:
1.抛弃了上面所说的三个钩子函数【其实还可以使用】
2.新添加了两个钩子函数
现在重点说一下,新添加的钩子函数
static getDerivedStateFromProps(props, state)
首先,该函数会调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用;该函数必须是静态的;给组件传递的数据(props)以及组件状态(state),会作为参数到这个函数中;该函数也必须有返回值,返回一个Null或者state对象。因为初始化和后续更新都会执行这个方法,因此在这个方法返回state对象,就相当于将原来的state进行了覆盖,所以倒是修改状态不起作用。
getSnapshotBeforeUpdate(prevProps, prevState)
getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递componentDidUpdate()。
补充一下:componentDidUpdate(prevProps, prevState, snapshot)
该生命周期函数,可以有三个参数:原始传过来的参数,最开始的状态,getSnapshotBeforeUpdate传递的值
关于更多关于生命周期的介绍,可以参考官方文档:
https://zh-hans.reactjs.org/docs/react-component.html#render
以上就是两个新添加的钩子函数,但是在现实开发中可能并不常用这两个。
**案例:在一个区域内,定时的输出以行话,如果内容大小超过了区域大小,就出现滚动条,但是内容不进行移动 **
如上面的动图:区域内部的内容展现没有变化,但是可以看见滚动条在变化,也就是说上面依旧有内容在输出,只不过不在这个区域内部展现。
实现:
【一些css样式,就不在这展示了】
1.首先我们先实现定时输出内容
我们可以使用state状态,改变新闻后面的值,但是为了同时显示这些内容,我们应该为state的属性定义一个数组。并在创建组件之后开启一个定时器,不断的进行更新state。更新渲染组件
class New extends React.Component{
state = {num:[]};
//在组件创建之后,开启一个定时任务
componentDidMount(){
setInterval(()=>{
let {num} = this.state;
const news = (num.length+1);
this.setState({num:[news,...num]});
},2000);
}
render(){
return (
<div ref = "list" className = "list">{
this.state.num.map((n,index)=>{
return <div className="news" key={index} >新闻{n}</div>
})
}</div>
)
}
}
ReactDOM.render(<New />,document.getElementById("div"));
2.接下来就是控制滚动条了
我们在组件渲染到DOM之前获取组件的高度,然后用组件渲染之后的高度减去之前的高度就是一条新的内容的高度,这样在不断的累加到滚动条位置上。
getSnapshotBeforeUpdate(){
return this.refs.list.scrollHeight;
}
componentDidUpdate(preProps,preState,height){
this.refs.list.scrollTop += (this.refs.list.scrollHeight - height);
}
这样就实现了这个功能。