持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第15天,点击查看活动详情
组件的生命周期
需求:
- 定义一个<h2>标签,实现在2s时间内逐渐透明的效果。
- 创建一个按钮,点击按钮销毁当前组件。
基础页面
首先,我们先把基础的页面实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件的生命周期</title>
</head>
<body>
<!-- 测试容器 -->
<div id="test"></div>
<!-- 加载 React 核心库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- 加载 React DOM 用于支持 React 操作 DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!-- 加载 babel 用于将 jsx 转为 js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<!-- 设置类型为babel -->
<script type="text/babel">
class Life extends React.Component {
state = {opacity: 1}
// 卸载组件
kill = () => {
ReactDOM.unmountComponentAtNode(document.getElementById("test"))
}
render() {
return (
<div>
<h2 style={{opacity: this.state.opacity}}>React学不会怎么办?</h2>
<button onClick={this.kill}>不学了,毁灭吧!</button>
</div>
)
}
}
ReactDOM.render(<Life />, document.getElementById("test"))
</script>
</body>
</html>
效果图:
渐隐效果
setInterval(() => {
let {opacity} = this.state
opacity = opacity <= 0.1 ? 1 : opacity - 0.1
this.setState({opacity})
}, 200)
可能有一些小伙伴想着既然是按钮要调用的,那么就把该函数放在类里面去实现,直接放里面编译器会报错:
于是换个地方:
放在render()函数里面了,没报错,看来可行,但是,小伙伴们要记得,render函数的调用次数是n+1的,初始化的时候会执行一次,以后每次状态修改都会被调用,如果将定时任务放在这里面的话,该任务又涉及到了状态的更改,那么他就会陷入一种无限递归状态,一只持续的调用render函数。不相信的小伙伴们可以看下控制台打印的日志:
render() {
console.log(1)
setInterval(() => {
let {opacity} = this.state
opacity = opacity <= 0.1 ? 1 : opacity - 0.1
this.setState({opacity})
}, 200)
return (
<div>
<h2 style={{opacity: this.state.opacity}}>React学不会怎么办?</h2>
<button onClick={this.kill}>不学了,毁灭吧!</button>
</div>
)
}
调用次数成指数级疯狂的上涨:
那么我们到底应该怎么实现该功能呢?在React中,他有提供一个函数给我们使用componentDidMount,它在当前组件被挂载完成之后,就会被调用执行一次,因此,我们可以通过它来实现我们需要的功能
// 组件挂载完毕调用
componentDidMount() {
setInterval(() => {
let { opacity } = this.state
opacity = opacity <= 0.1 ? 1 : opacity - 0.1
this.setState({ opacity })
}, 200)
}
现在效果实现了,逐渐透明的效果正常,点击按钮也能正常销毁组件了,但是控制台这边又报了一个错误,它的意思说说无法对销毁的组件执行状态更新。
原来是我们没有直接销毁了组件,但是定时器并没有被清除,还一直被执行着,那么我们需要将它清除掉才行。在刚刚的控制台异常提示中已经给出了我们提示了,我们可以直接定义该函数来实现清除定时器的逻辑。
// 组件挂载完毕调用
componentDidMount() {
this.times = setInterval(() => {
let { opacity } = this.state
opacity = opacity <= 0.1 ? 1 : opacity - 0.1
this.setState({ opacity })
}, 200)
}
// 组件销毁时执行
componentWillUnmount(){
clearTimeout(this.times)
}