案例:
定义组件实现以下功能:
- 让指定的文本做显示/隐藏的渐变动画
- 从完全可见,到彻底消失,耗时2s
- 点击“消失”按钮从界面中卸载组件
<script type="text/babel">
//创建组件
//生命周期(回调)函数<=>生命周期钩子(函数)
class Life extends React.Component{
state = {opacity:1}
death=()=>{
//卸载组件
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
//组件挂载完毕调用
componentDidMount(){
setInterval(()=>{
//获取原状态
let {opacity} = this.satae
//减小0.1
opacity -= 0.1
if(opacity <= 0) opacity = 1
//设置新的透明度
this.setState({opacity})
},200);
}
//组件将要卸载
componentWillUnmount(){
//清除定时器
clearInterval(this.timer)
}
//初始化渲染、状态更新之后
render(){
return(
<div>
<h2 style={{opacity:this.state.opacity}}>什么是快乐星球?</h2>
<button onClick={this.death}>消失</button>
</div>
)
}
}
//2、渲染组件到页面
ReactDOM.render(<Life/>,document.getElementById('test'))
</script>
生命周期:
- 组件从创建到死亡它会经历一些特定的阶段。
- React组件中包含一系列勾子函数(生命周期回调函数),会在特定的时刻调用。
- 我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。
推荐React&生命周期官方文档:https://react.docschina.org/docs/state-and-lifecycle.html
B站相关视频:https://www.bilibili.com/video/BV1wy4y1D7JT?p=39&spm_id_from=pageDriver
生命周期的三个阶段(旧)
1、初始化阶段:由ReactDOM.render()触发–初次渲染
- constructor()
- componentWillMount()
- render()
- componentDidMount()做初始化,例如:开启定时器
2、更新阶段:由组件内部this.setState()或父组件更新render触发 - shouldComponentUpdate()
- componentWillUpdate
- render() 必须使用
- componentDidUpdate()
3、组件卸载:由ReactDOM.unmountComponentAtNode()触发 - componentWillUnmount()做结束,例如:关闭定时器,取消定时器
旧生命周期图如下:
对于react新生命周期和旧生命周期的区别:
新的生命周期和旧的生命周期相比,即将废弃了3个勾子函数,即:componentWillMount 、conponentWillReceiveProps 、compoentWillUpdate 提出了两个新的勾子函数:getDerivedStateFromProps 、getSnapshshotBeforeUpdate
新生命周期图如下:
getDerivedStateFromProps
static getDerivedStateFromProps(props, state)
getDerivedStateFromProps 会在调用 render
方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。此方法适用于罕见的用例,即 state 的值在任何时候都取决于 props。例如,实现
组件可能很方便,该组件会比较当前组件与下一组件,以决定针对哪些组件进行转场动画。 派生状态会导致代码冗余,并使组件难以维护。
确保你已熟悉这些简单的替代方案:如果你需要执行副作用(例如,数据提取或动画)以响应 props 中的更改,请改用 componentDidUpdate。 如果只想在
prop 更改时重新计算某些数据,请使用 memoization helper 代替。 如果你想在 prop 更改时“重置”某些
state,请考虑使组件完全受控或使用 key 使组件完全不受控 代替。 此方法无权访问组件实例。如果你需要,可以通过提取组件 props
的纯函数及 class 之外的状态,在getDerivedStateFromProps()和其他 class 方法之间重用代码。请注意,不管原因是什么,都会在每次渲染前触发此方法。这与 UNSAFE_componentWillReceiveProps
形成对比,后者仅在父组件重新渲染时触发,而不是在内部调用 setState 时。
getSnapshotBeforeUpdate()
getSnapshotBeforeUpdate(prevProps, prevState)
getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM
中捕获一些信息(例如,滚动位置)。此生命周期方法的任何返回值将作为参数传递给 componentDidUpdate()。此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。
应返回 snapshot 的值(或 null)。
例如:
class ScrollingList extends React.Component { constructor(props) {
super(props);
this.listRef = React.createRef(); }
getSnapshotBeforeUpdate(prevProps, prevState) {
// 我们是否在 list 中添加新的 items ?
// 捕获滚动位置以便我们稍后调整滚动位置。
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null; }
componentDidUpdate(prevProps, prevState, snapshot) {
// 如果我们 snapshot 有值,说明我们刚刚添加了新的 items,
// 调整滚动位置使得这些新 items 不会将旧的 items 推出视图。
//(这里的 snapshot 是 getSnapshotBeforeUpdate 的返回值)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
} }
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
); } }
在上述示例中,重点是从 getSnapshotBeforeUpdate 读取 scrollHeight 属性,因为 “render”
阶段生命周期(如 render)和 “commit” 阶段生命周期(如 getSnapshotBeforeUpdate 和 componentDidUpdate)之间可能存在延迟。
生命周期的三个阶段(新)
1、初始化阶段:由ReactDOM.render()触发—初次渲染
- construct()
- getDerivedStateFromProps
- render()
- componentDidMount()
2、更新阶段:由组件内部this.setState()或父组件更新render触发 - getDerivedStateFromProps
- shouldComponentUpdate()
- render()
- getSnapshotBeforeUpdate
- componentDidUpdate()
3、卸载组件:由ReactDOM.unmountComponentAtNode()触发
- componentWillUnmount()