每天学点React - 组件的生命周期(一)

75 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第15天,点击查看活动详情

组件的生命周期

需求:

  1. 定义一个<h2>标签,实现在2s时间内逐渐透明的效果。
  2. 创建一个按钮,点击按钮销毁当前组件。

基础页面

首先,我们先把基础的页面实现

<!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>

效果图:

image.png

渐隐效果

setInterval(() => {
    let {opacity} = this.state
    opacity = opacity <= 0.1 ? 1 : opacity - 0.1
    this.setState({opacity})
}, 200)

可能有一些小伙伴想着既然是按钮要调用的,那么就把该函数放在类里面去实现,直接放里面编译器会报错:

image.png

于是换个地方:

image.png

放在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>
    )
}

调用次数成指数级疯狂的上涨: image.png

那么我们到底应该怎么实现该功能呢?在React中,他有提供一个函数给我们使用componentDidMount,它在当前组件被挂载完成之后,就会被调用执行一次,因此,我们可以通过它来实现我们需要的功能

// 组件挂载完毕调用
componentDidMount() {
    setInterval(() => {
        let { opacity } = this.state
        opacity = opacity <= 0.1 ? 1 : opacity - 0.1
        this.setState({ opacity })
    }, 200)
}

现在效果实现了,逐渐透明的效果正常,点击按钮也能正常销毁组件了,但是控制台这边又报了一个错误,它的意思说说无法对销毁的组件执行状态更新。

image.png

原来是我们没有直接销毁了组件,但是定时器并没有被清除,还一直被执行着,那么我们需要将它清除掉才行。在刚刚的控制台异常提示中已经给出了我们提示了,我们可以直接定义该函数来实现清除定时器的逻辑。

// 组件挂载完毕调用
componentDidMount() {
    this.times = setInterval(() => {
        let { opacity } = this.state
        opacity = opacity <= 0.1 ? 1 : opacity - 0.1
        this.setState({ opacity })
    }, 200)
}

// 组件销毁时执行
componentWillUnmount(){
    clearTimeout(this.times)
}

image.png