组件编程-组件生命周期
案例需求
- 让指定的文本做显示 / 隐藏的渐变动画
- 从完全可见,到彻底消失,耗时2S
- 点击“不活了”按钮从界面中卸载组件
案例展示
需求引出生命周期
<script type="text/babel">
class Life extends React.Component{
state = {
opacity:1
}
RemoveComponent = event=>{
ReactDOM.unmountComponentAtNode(document.getElementById("test"))
}
componentWillUnmount(){
clearInterval(this.timer)
}
componentDidMount(){
let {opacity} = this.state;
this.timer = setInterval(()=>{
opacity -= 0.1;
if(opacity <= 0) opacity = 1;
this.setState({opacity})
}, 200)
}
render(){
return (
<div>
<h3 style={{opacity:this.state.opacity}}>react 学不会, 怎么办</h3>
<button onClick={this.RemoveComponent}>不活了</button>
</div>
)
}
}
ReactDOM.render(<Life/>, document.getElementById("test"))
</script>
componentWillUnmount(){}
- 组件卸载前回调componentDidMount(){}
- 组件挂载后回调render(){}
- 组件调用
概念
- 组件从创建到死亡它会经历一些特定的阶段
- React组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用
- 生命周期回调函数
- 生命周期钩子函数
- 生命周期函数
- 生命周期钩子
- 我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作
总结
重要的钩子
render
:初始化渲染或更新渲染调用componentDidMount
:开启监听, 发送ajax请求componentWillUnmount
:做一些收尾工作, 如: 清理定时器
17版即将废弃的钩子
componentWillMount
componentWillReceiveProps
componentWillUpdate
现在使用会出现警告,下一个大版本需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用
老版生命周期-17版前
初始化阶段
: 由ReactDOM.render()
触发, 初次渲染constructor()
- 构造器componentWillMount()
- 挂载前调用render()
- 组件挂载(渲染)- ==
componentDidMount()
- 挂载后调用==- 一般作用为初始化 例如: 开启定时器, 发送网络请求, 订阅消息…
更新阶段
: 由组件内部this.setState()
或父组件render
触发componentWillReceiveProps()
- 接收新的props- ==这个第二次传入props调用==
shoudComponentUpdate()
- 判断组件是否应该更新了( 默认为真 )componentWillUpdate()
- 组件将要更新- ==
render()
- 组件挂载(渲染)== componentDidUpdate()
- 组件完成更新
卸载阶段
: 由ReactDOM.unmountComponentAtNode()
触发- ==
componentWillUnmount()
- 组件将要卸载==- 一般作用为一些收尾工作 例如, 关闭定时器, 取消订阅消息…
- ==
案例: (挂载时)按键后计数++
<script type="text/babel">
class Count extends React.Component{
// 构造函数
constructor(props){
console.log("Conut--constructor()")
super(props)
this.state = {count:0}
}
// 组件将挂载钩子
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()")
}
// 按钮+1
add = event=>{
const {count} = this.state;
this.setState({count:count+1})
}
// 组件卸载
remove = event=>{
ReactDOM.unmountComponentAtNode(document.getElementById("test"))
}
// 组件强制刷新
force = event=>{
this.forceUpdate();
}
render(){
console.log("Count--render()")
const {count} = this.state
return (
<div>
<h3>当前计数为{count}</h3>
<button onClick={this.add}>计数++</button>
<button onClick={this.remove}>卸载组件</button>
<button onClick={this.force}>不刷新状态, 强制更新</button>
</div>
)
}
}
ReactDOM.render(<Count/>, document.getElementById("test"))
</script>
案例: (父组件)换车~
<script type="text/babel">
class A extends React.Component{
state = {carname:"奔驰"}
changeCar = ()=>{
this.setState({carname:"奥托"})
}
render(){
const {carname} = this.state
return (
<div>
<div>我是组件A</div>
<button onClick={this.changeCar}>按下按键更新换车</button>
<B carname={this.state.carname}/>
</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 (
<div>
<h3>我的车是 {this.props.carname}</h3>
</div>
)
}
}
ReactDOM.render(<A/>, document.getElementById("test"))
</script>
新版本生命周期-17版及后
- 初始化阶段: 由
ReactDOM.render()
触发, 初次渲染constructor()
- 构造器getDerivedStateFromProps()
- 若
state
的值在任何时候都取决于props
,那么可以使用etDerivedStateFromProps()
- 也可以直接使用构造器
- 若
render()
- ==
componentDidMount()
- 组件完成挂载==- 一般作用为初始化 例如: 开启定时器, 发送网络请求, 订阅消息…
- 更新阶段: 由组件内部
this.setState()
或父组件render
触发getDerivedStateFromProps()
- 若
state
的值在任何时候都取决于props
,那么可以使用etDerivedStateFromProps()
- 也可以直接使用构造器
- 若
shoudComponentUpdate()
- 组件判断是否应该更新- ==
render()
- 组件挂载(渲染)== getSnapshotBeforeUpdate()
- 更新之前获取快照componentDidUpdate()
- 组件完成更新
卸载阶段
: 由ReactDOM.unmountComponentAtNode()
触发- ==
componentWillUnmount()
- 组件将要卸载==- 一般作用为一些收尾工作 例如, 关闭定时器, 取消订阅消息…
- ==
getSnapshotBeforeUpdate()
-鲜有的应用场景
滚动页面定位
<style>
.list{
height: 150px;
width: 300px;
background-color: aqua;
overflow: auto;
}
.news{
height: 30px;
}
</style>
<script type="text/babel">
class NewList extends React.Component{
state = {newsArr:[]}
componentDidMount(){
setInterval(()=>{
const {newsArr} = this.state; // 获取原状态
const news = "新闻"+(newsArr.length+1); // 模拟的一条新增新闻
this.setState({newsArr:[news, ...newsArr]})
}, 1000)
}
getSnapshotBeforeUpdate(){
return this.refs.list.scrollHeight; // 获取当前列表总高
}
/* (preProps,preState,snapshotValue) */
componentDidUpdate(preProps, preState, height){
// 右值等于一个新闻高度
// 左值为已经偏移完的高度
return this.refs.list.scrollTop += this.refs.list.scrollHeight - height;
}
render(){
return(
<div className="list" ref="list">
{
/* n 表示遍历后的节点对象 */
this.state.newsArr.map((n, index)=>{
return(
<div key={index} className="news">{n}</div>
)
})
}
</div>
)
}
}
ReactDOM.render(<NewList/>, document.getElementById("test"))
</script>