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

53 阅读2分钟

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

组件的生命周期

事先准备

我们在页面中添加一个按钮,每次点击时变量自增1,在页面中将该数值显示出来,效果图如下:

image.png

案例代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>react的生命周期(旧)</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 Count extends React.Component {
            // 初始化状态
            state = { count: 0 }

            // 按钮回调
            addOne = () => {
                // 获取原状态
                const { count } = this.state
                // 更新状态
                this.setState({ count: count + 1 })
            }

            render() {
                const { count } = this.state
                return (
                    <div>
                        <h2>当前求和为:{count}</h2>
                        <button onClick={this.addOne}>增加 1</button>
                    </div>
                )
            }
        }

        ReactDOM.render(<Count />, document.getElementById("test"))
    </script>
</body>

</html>

生命周期的引入

react生命周期(旧).png

上面的图是React生命周期的执行顺序图,实际上是不是这样呢?我们将涉及到的勾子函数都实现一下,在控制台打印出来看一下是不是这样

组件挂载顺序:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>react的生命周期(旧)</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 Count extends React.Component {

            // 构造函数
            constructor(props) {
                console.log('Count: constructor')
                super(props)
                // 初始化状态
                this.state = { count: 0 }
            }

            // 组件挂载前执行
            componentWillMount(){
                console.log('Count: componentWillMount')
            }

            // 组件挂载后执行
            componentDidMount(){
                console.log('Count: componentDidMount')
            }

            // 挂载组件
            render() {
                console.log('Count: render')
                const { count } = this.state
                return (
                    <div>
                        <h2>当前求和为:{count}</h2>
                        <button onClick={this.addOne}>增加 1</button>
                    </div>
                )
            }

            // 按钮回调
            addOne = () => {
                // 获取原状态
                const { count } = this.state
                // 更新状态
                this.setState({ count: count + 1 })
            }
        }

        ReactDOM.render(<Count />, document.getElementById("test"))
    </script>
</body>

</html>

下图中可以看到,组件确实是按照这个顺序进行挂载的: image.png

shouldComponentUpdate

该函数用来控制组件的状态更新,当其返回true时允许状态更新,返回false时则拒绝状态更新,不自定义该函数当话默认返回true

自定义不返回时的效果:

shouldComponentUpdate(){
    console.log('Count: shouldComponentUpdate')
}

image.png

返回false时的效果:

shouldComponentUpdate(){
    console.log('Count: shouldComponentUpdate')
    return false
}

image.png

返回true时的效果:

shouldComponentUpdate(){
    console.log('Count: shouldComponentUpdate')
    return true
}

image.png

在上图的效果我们可以看到,当更新的阀门返回true时,组件还触发来更新前与更新后的勾子函数,上面的这个流程顺序为:

setState() -> shouldComponentUpdate() -> componentWillUpdate() -> render() -> componentDidUpdate()

是常规的更新顺序,图中还有一个强制更新函数,它不需要通过状况控制的阀门即可实现组件更新:

// 新增一个强制更新按钮
<button onClick={this.force}>强制更新</button>

// 添加按钮回调
force = () => {
    this.forceUpdate()
}

图中可以看到,shouldComponentUpdate函数并没有被执行: image.png

上面说了setStateforceupdate这两条线路,我们再说一下父组件componentWillReceiveProps的这条线路吧

需要注意的是,该函数在组件第一次渲染时并不会触发,只有当祖父件状态更新,从新render时,子组件才会触发该函数

class Facher extends React.Component {
            state = { name: '张三' }

            changeName = () => {
                this.setState({ name: '张三三' })
            }

            render() {
                return (
                    <div>
                        <h2>我是父组件</h2>
                        <button onClick={this.changeName}>改名</button>
                        <Children name={this.state.name} />
                    </div>
                )
            }
        }

        class Children extends React.Component {

            componentWillReceiveProps(){
                console.log('Children: componentWillReceiveProps')
            }

            render() {
                return (
                    <div>
                        <h2>我是子组件,名字是:{this.props.name}</h2>
                    </div>
                )
            }
        }

        ReactDOM.render(<Facher />, document.getElementById("test"))

初始化读取父组件props时:

image.png

父组件更新状态从新render时: image.png