前端开发那些事儿

【React】4.0 组件的生命周期

2021-06-08  本文已影响0人  bobokaka
1.0 生命周期的理解
  1. 组件从创建到死亡它会经历一些特定的阶段。
  2. React组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用。
  3. 我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。

首先创建如下代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>hello_react</title>
  </head>
  <!-- 1.0 准备容器 -->
  <div id="test"></div>
  <!-- 2.0引入react核心库 -->
  <script type="text/javascript" src="../js/react.development.js"></script>
  <!-- 3.0 引入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>
  <!-- 引入prop-types,用于对组件标签属性进行限制 -->
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <script type="text/babel">
        //创建组件
        class Life extends React.Component{
            //初始化渲染、状态更新之后
            render(){
                console.log('render');
                return(
                    <div>
                        <h2>React学不会怎么办?</h2>
                        <button>不活了</button>
                    </div>
                )
            }
        }
        //渲染组件
        ReactDOM.render(<Life/>,document.getElementById('test'))
    </script>
  </body>
</html>

image.png

目的:让上面文本自动透明变不透明,渐变切换。

当Clock组件第一次被渲染到DOM中的时候,魏骑设置一个定时器。这种在React中被称之为“挂载(mount)”,所以从DOM中删除Clock组件时,清除计时器,在React中被称之为“卸载(unmount)”。

    <script type="text/babel">
        //创建组件
        class Life extends React.Component{

            death=()=>{
                        //卸载组件
                        ReactDOM.unmountComponentAtNode(document.getElementById('test'))
            }

            //初始化渲染、状态更新之后
            render(){
                console.log('render');
                return(
                    <div>
                        <h2>React学不会怎么办?</h2>
                        <button onClick={this.death}>不活了</button>
                    </div>
                )
            }
        }
        //渲染组件
        ReactDOM.render(<Life/>,document.getElementById('test'))
    </script>

运行,点击按钮就是卸载,刷新页面自然就出现挂载行为。

透明度发生变化,自然是状态中的数据在驱动。

    <script type="text/babel">
        //创建组件
        class Life extends React.Component{
        //状态:透明度
        state = {opacity:1}

            death=()=>{
                        //卸载组件
                        ReactDOM.unmountComponentAtNode(document.getElementById('test'))
            }

            //初始化渲染、状态更新之后
            render(){
                console.log('render');
                return(
                    <div>
                        <h2 style={{opacity:this.state.opacity}}>React学不会怎么办?</h2>
                        <button onClick={this.death}>不活了</button>
                    </div>
                )
            }
        }
        //渲染组件
        ReactDOM.render(<Life/>,document.getElementById('test'))
    </script>

接下来需要透明度不断地发生变化。

    <script type="text/babel">
        //创建组件
        //生命周期回调函数 <=> 生命周期钩子函数 <=> 生命周期函数 <=> 生命周期钩子
        class Life extends React.Component{

            state = {opacity:1}

            death = ()=>{
                //卸载组件
                ReactDOM.unmountComponentAtNode(document.getElementById('test'))
            }

            //组件挂完毕
            componentDidMount(){
                console.log('componentDidMount');
                this.timer = setInterval(() => {
                    //获取原状态
                    let {opacity} = this.state
                    //减小0.1
                    opacity -= 0.1
                    if(opacity <= 0) opacity = 1
                    //设置新的透明度
                    this.setState({opacity})
                }, 200);
            }

            //组件将要卸载
            componentWillUnmount(){
                //清除定时器
                clearInterval(this.timer)
            }

            //初始化渲染、状态更新之后
            render(){
                console.log('render');
                return(
                    <div>
                        <h2 style={{opacity:this.state.opacity}}>React学不会怎么办?</h2>
                        <button onClick={this.death}>不活了</button>
                    </div>
                )
            }
        }
        //渲染组件
        ReactDOM.render(<Life/>,document.getElementById('test'))
    </script>
2.0 旧的生命周期
image.png
2.1 挂载

生命周期在代码中出现的顺序和执行顺序无关。

    <script type="text/babel">
        //创建组件
        class Count extends React.Component{
        //初始化状态
        state={count:0}

                    //加1按钮的回调
        add = ()=>{
                        //获取原状态
                        const {count} = this.state
                        //更新状态
                        this.setState({count:count+1})
        }
        render(){
                //获取原状态
                const {count} = this.state
                return(
                    <div>
                        <h2>当前求和为:{count}</h2>
                        <button onClick={this.add}>点我+1</button>
                    </div>
                )
            }
            }
        
        //渲染组件
        ReactDOM.render(<Count/>,document.getElementById('test'))
    </script>

按图来 直接上测试代码:


    <script type="text/babel">
        //创建组件
        class Count extends React.Component{
        //构造器
        constructor(props){
            console.log('Count---constructor');
            super(props)
            //初始化状态
            this.state = {count:0}
        }

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

        
        //组件将要挂载的钩子
            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.add}>点我+1</button>
                    </div>
                )
            }
            }
        
        //渲染组件
        ReactDOM.render(<Count/>,document.getElementById('test'))
    </script>

(一般构造器写在最前面)


image.png
2.2 卸载
    <script type="text/babel">
        //创建组件
        class Count extends React.Component{
        //构造器
        constructor(props){
            console.log('Count---constructor');
            super(props)
            //初始化状态
            this.state = {count:0}
        }

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

        //卸载组件按钮的回调
        death = ()=>{
            ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }

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

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

        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>
                    </div>
                )
        }
    }
        
        //渲染组件
        ReactDOM.render(<Count/>,document.getElementById('test'))
    </script>

点击“卸载组件”:


image.png
2.3 更新

更新可以分为3种情况:


image.png

其中最正常的情况,是第二种。

2.4 setState涉及的更新

    <script type="text/babel">
        //创建组件
        class Count extends React.Component{
        //构造器
        constructor(props){
            console.log('Count---constructor');
            super(props)
            //初始化状态
            this.state = {count:0}
        }

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

        //卸载组件按钮的回调
        death = ()=>{
            ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }

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

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

        //控制组件更新的“阀门”:组件是否应该被更新:true:false
        shouldComponentUpdate(){
            console.log('Count---shouldComponentUpdate');
            return true
        }

        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>
                    </div>
                )
        }
    }
        
        //渲染组件
        ReactDOM.render(<Count/>,document.getElementById('test'))
    </script>
image.png
shouldComponentUpdate必须有返回值,如果不自定义写,React也会给一个默认的勾子函数,并永远返回true

    <script type="text/babel">
        //创建组件
        class Count extends React.Component{
        //构造器
        constructor(props){
            console.log('Count---constructor');
            super(props)
            //初始化状态
            this.state = {count:0}
        }

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

        //卸载组件按钮的回调
        death = ()=>{
            ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }

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

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

        //控制组件更新的“阀门”:组件是否应该被更新:true:false
        shouldComponentUpdate(){
            console.log('Count---shouldComponentUpdate');
            return true
        }

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

        //组件更新完毕的钩子
        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>
                    </div>
                )
        }
    }
        
        //渲染组件
        ReactDOM.render(<Count/>,document.getElementById('test'))
    </script>
image.png
2.5 forceUpdate()涉及的更新

force:军队、武装、强制。这里指的是强制更新。
只比正常流程少一步绕过阀门。

    <script type="text/babel">
        //创建组件
        class Count extends React.Component{
        //构造器
        constructor(props){
            console.log('Count---constructor');
            super(props)
            //初始化状态
            this.state = {count:0}
        }

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

        //强制更新按钮的回调
        force = ()=>{
            this.forceUpdate()
        } 
        //卸载组件按钮的回调
        death = ()=>{
            ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }

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

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

        //控制组件更新的“阀门”:组件是否应该被更新:true:false
        shouldComponentUpdate(){
            console.log('Count---shouldComponentUpdate');
            return true
        }

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

        //组件更新完毕的钩子
        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>
                )
        }
    }
        
        //渲染组件
        ReactDOM.render(<Count/>,document.getElementById('test'))
    </script>
image.png
2.6 父组件render涉及的更新

将Count组件折叠,创建两个组件A、B, 让AB形成父子关系。

    <script type="text/babel">
        //创建组件
        class Count extends React.Component{...

        //父组件A
        class A extends React.Component{

            render(){
                return(
                    <div>
                        <div>我是A组件</div>
                        <B />
                    </div>
                )
            }
        }
        
        //子组件B
        class B extends React.Component{
            render(){
                return(
                    <div>我是B组件</div>
                )
            }
        }
        
        //渲染组件
        ReactDOM.render(<A/>,document.getElementById('test'))
    </script>
image.png

如下需求:A组件更改信息,由B组件展示信息。

    <script type="text/babel">
        //创建组件
        class Count extends React.Component{...

    //父组件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{
            render(){
                return(
                    <div>我是B组件,接收到的车是:{this.props.carName}</div>
                )
            }
        }
        
        //渲染组件
        ReactDOM.render(<A/>,document.getElementById('test'))
    </script>
image.png
    <script type="text/babel">
        //创建组件
        class Count extends React.Component{...

    //父组件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{

            //组件将要接收新的props的钩子
            componentWillReceiveProps(props){
                console.log('B---componentWillReceiveProps',props);
            }
            
            //控制组件更新的“阀门”
            shouldComponentUpdate(){
                console.log('B---shouldComponentUpdate');
                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(<A/>,document.getElementById('test'))
    </script>

这里有一个问题,componentWillReceiveProps方法执行第一次不执行。


image.png

完成代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>2_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>

    <script type="text/babel">
        /* 
                1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
                                    1.  constructor()
                                    2.  componentWillMount()
                                    3.  render()
                                    4.  componentDidMount() =====> 常用
                                                    一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
                2. 更新阶段: 由组件内部this.setSate()或父组件render触发
                                    1.  shouldComponentUpdate()
                                    2.  componentWillUpdate()
                                    3.  render() =====> 必须使用的一个
                                    4.  componentDidUpdate()
                3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
                                    1.  componentWillUnmount()  =====> 常用
                                                    一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
        */
        //创建组件
        class Count extends React.Component{

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

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

            //卸载组件按钮的回调
            death = ()=>{
                ReactDOM.unmountComponentAtNode(document.getElementById('test'))
            }

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

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

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

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

            //控制组件更新的“阀门”:组件是否应该被更新
            shouldComponentUpdate(){
                console.log('Count---shouldComponentUpdate');
                return true
            }

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

            //组件更新完毕的钩子
            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>
                )
            }
        }
        
        //父组件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{
            //组件将要接收新的props的钩子
            componentWillReceiveProps(props){
                console.log('B---componentWillReceiveProps',props);
            }

            //控制组件更新的“阀门”
            shouldComponentUpdate(){
                console.log('B---shouldComponentUpdate');
                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'))
    </script>
</body>
</html>
3.0 新的生命周期

增加了2个新的勾子函数,废弃了原来的3个勾子函数。


image.png
上一篇 下一篇

猜你喜欢

热点阅读