1 生命周期的理解

1.1 引出生命周期

需求:

  1. 让指定的文本做显示* / 隐藏的渐变动画
  2. 从完全可见,到彻底消失,耗时2S
  3. 点击“不活了”按钮从界面中卸载组件

源码及笔记如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
    class Life extends React.Component {
        //只要页面发生更新,则说明是状态在驱动
        state = {
            opacity: 0.5
        }

        death = () => {
            ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }

        //和render一样 是由React帮忙调用的 因此不用写成箭头函数的形式
        //执行时机:组件挂载到页面后
        componentDidMount() {
            //起个名字 挂到实例自身 方便清除时用
            this.timer = setInterval(() => {
                //获取状态值
                let opacity = this.state.opacity
                //每次-0.1
                opacity -= 0.1
                if (opacity <= 0) opacity = 1
                //设置新的透明度
                this.setState({ opacity })
            }, 200)
        }

        //执行时机:组件将要被卸载
        componentWillUnmount() {
            clearInterval(this.timer)
        }

        //执行时机:初始化渲染、状态更新后
        render() {
            //如果将定时器函数放到render中,那么由于定时器中更新了state值,render函数就会不断被调用
            //从而形成无限递归
            // setInterval(() => {
            //     //获取状态值
            //     let opacity = this.state.opacity
            //     //每次-0.1
            //     opacity -= 0.1
            //     if (opacity <= 0) opacity = 1
            //     //设置新的透明度
            //     this.setState({ opacity })
            // }, 200)
            return (
                <div>
                    <h2 style={{ opacity: this.state.opacity }}>React学不会怎么办</h2>
                    <button onClick={this.death}>不活了</button>
                </div>
            )
        }
    }
    ReactDOM.render(<Life />, document.getElementById('test'))

1.2 生命周期的理解

合适的时间节点做合适的事

  1. 组件从创建到死亡它会经历一些特定的阶段。
  2. React 组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用。
  3. 我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。

2 React生命周期(旧)

2.1 React生命周期图(旧)

react生命周期(旧)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
	class Count extends React.Component {
        //构造器
        constructor(props) {
            super(props)
            console.log('Count---constructor');
            //初始化状态
            this.state = { count: 0 }
        }

        //组件将要挂载的钩子
        componentWillMount() {
            console.log('Count---componentWillMount');
        }

        //组件是否更新的钩子 相当于"阀门"
        shouldComponentUpdate() {
            console.log('Count---shouldComponentUpdate');
            return true
        }

        //组件将要更新的钩子
        componentWillUpdate() {
            console.log('Count---componentWillUpdate');
        }

        // 加一事件的回调
        add = () => {
            const { count } = this.state
            this.setState({ count: count + 1 })
        }

        //强制更新组件的回调
        force = () => {
            this.forceUpdate()
        }

        //组件更新完毕的钩子
        componentDidUpdate() {
            console.log('Count---componentDidUpdate');
        }

        render() {
            console.log('Count---render');
            const { count } = this.state
            return (
                <div>
                    <h2>当前求和为{count}</h2>
                    <button onClick={this.add}>点我+1</button>
                    <button onClick={this.death}>卸载组件</button>
                    <button onClick={this.force}>不更新状态只是强制更新一下组件</button>
                </div>
            )
        }

        //组件挂载完毕的钩子
        componentDidMount() {
            console.log('Count---componentDidMount');
        }

        //组件将要卸载的钩子
        componentWillUnmount() {
            console.log('Count---conponentWillUnmount');
        }

        death = () => {
            ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }
    }

    //父组件A
    class A extends React.Component {
        //初始化状态
        state = {
            carName: '奔驰'
        }

        changeCar = () => {
            this.setState({ carName: '奥迪' })
        }

        render() {
            return (
                <div>
                    <div>我是A组件</div>
                    <button onClick={this.changeCar}>点我切换汽车信息</button>
                    <B carName={this.state.carName} />
                </div>
            )
        }
    }

    //子组件B
    class B extends React.Component {

        //第一次打开界面 发现其未运行 点击按钮后才会运行此钩子
        //改名为componentWillReceiveNewProps更为准确
        //组件将要接收新的props的钩子
        componentWillReceiveProps() {
            console.log('B---componentWillReceiveProps', this.props);
        }

        //控制组件更新的阀门
        shouldComponentUpdate() {
            console.log('B---shouldComponentUpdate');
            //只要写了此钩子 必须return一个布尔值
            return true
        }

        //组件将要更新的钩子
        componentWillUpdate() {
            console.log('B---componentWillUpdate');
        }

        //组件更新完毕的钩子
        componentDidUpdate() {
            console.log('B---componentDidUpdate');
        }

        render() {
            console.log('B---render');
            return (
                <div>我是B组件接受到的汽车是{this.props.carName}</div>
            )
        }
    }

    ReactDOM.render(<Count />, document.getElementById('test'))

2.2 总结生命周期(旧)

生命周期的三个阶段(旧):

  1. 初始化阶段: 由 ReactDOM.render()触发—初次渲染

​ 1. constructor()

 2. componentWillMount() 
   
 3. render()
   
 4. **componentDidMount**()

​ 一般在此钩子中做一些初始化的事:开启定时器,发送网络请求、订阅消息

  1. 更新阶段: 由组件内部 this.setSate()或父组件重新 render 触发

    ​ 1. shouldComponentUpdate()

    ​ 2. componentWillUpdate()

     3. **render**()
    

​ 4. componentDidUpdate()

  1. 卸载组件: 由 ReactDOM.unmountComponentAtNode()触发

    ​ 1. componentWillUnmount()

    ​ 一般做一些收尾的事:关闭定时器、取消订阅消息

2.3 React生命周期图(新)

react生命周期(新)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
	class Count extends React.Component {
        //构造器
        constructor(props) {
            super(props)
            console.log('Count---constructor');
            //初始化状态
            this.state = { count: 0 }
        }

        //通过props获取派生状态对象
        static getDerivedStateFromProps(props, state) {
            console.log('Count---getDerivedStateFromProps', props, state);
            return null//必须有返回值,返回值可以是null也可以是state对象
            //return {count:2}//会覆盖初始化的state,且影响更新过程,setState方法失效(因为横跨挂载和更新过程)
            //return props //可以接收props作为参数并返回 使得state值在任何时候都取决于props
        }

        //在更新之前获取快照
        getSnapshotBeforeUpdate() {
            console.log('Count---getSnapshotBeforeUpdate');
            return 'atguigu'//返回null或者snapshot值(任何值)
        }

        //组件是否更新的钩子 相当于"阀门"
        shouldComponentUpdate() {
            console.log('Count---shouldComponentUpdate');
            return true
        }

        // 加一事件的回调
        add = () => {
            const { count } = this.state
            this.setState({ count: count + 1 })
        }

        //强制更新组件的回调
        force = () => {
            this.forceUpdate()
        }

        //组件更新完毕的钩子
        //默认接收两个参数,分别是prevProps,prevState和snapshot值(例如滚轮位置)
        componentDidUpdate(prevProps, prevState, snapshot) {
            console.log('Count---componentDidUpdate', prevProps, prevState, snapshot);
        }

        render() {
            console.log('Count---render');
            const { count } = this.state
            return (
                <div>
                    <h2>当前求和为{count}</h2>
                    <button onClick={this.add}>点我+1</button>
                    <button onClick={this.death}>卸载组件</button>
                    <button onClick={this.force}>不更新状态只是强制更新一下组件</button>
                </div>
            )
        }

        //组件挂载完毕的钩子
        componentDidMount() {
            console.log('Count---componentDidMount');
        }

        //组件将要卸载的钩子
        componentWillUnmount() {
            console.log('Count---conponentWillUnmount');
        }

        death = () => {
            ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }
    }

    ReactDOM.render(<Count count={199} />, document.getElementById('test'))

2.4 总结生命周期(新)

生命周期的三个阶段(新)

1.初始化阶段: 由 ReactDOM.render()触发—初次渲染

  1. constructor() 
  
 2. **getDerivedStateFromProps**() 
  
 3. render() 

​ 4. componentDidMount() 即将出生的那一刻

2.更新阶段: 由组件内部 this.setSate()或父组件重新 render 触发

​ 1. getDerivedStateFromProps ()

​ 2. shouldComponentUpdate()

 3. **render**() 

​ 4. getSnapshotBeforeUpdate()

​ 5. componentDidUpdate()

  1. 卸载组件: 由 ReactDOM.unmountComponentAtNode()触发

    1. **componentWillUnmount**() 即将离去的那一刻
    

2.5 新旧生命周期对比

即将在18版本废除三个钩子(willmount,willupdate,willreceiveprops)

新增了两个钩子(getDerivedStateFromProps,getSnapshotBeforeUpdate)