12. React组件的生命周期

1.引出react的生命周期

1.1 一个需求

  • h2标签2秒内透明度从1到0
  • 如果透明度为0则立马初始为1
  • 一个按钮,点击按钮组件被卸载

1.2 组件的卸载(unmount)和装载(mount)

  • 装载: 组件被react加载都页面上展示
  • 卸载: 组件从页面上清除
  • 查看组件通过react 的 dev-tools查看工具

1.3 写出静态页面

  • 先写出静态页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>案例引出组件的生命周期</title>

</head>
<body>
    <div id="root"></div>
    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <script type="text/babel">
        class Life extends  React.Component{
            state={opacity:1}
            render(){
                return (
                    //只有一个根节点元素
                    <div>
                        <h2>React学不会怎么办</h2>
                        <button onClick={this.death}>不活了</button>
                    </div>
                );
            }
        }
        ReactDOM.render(<Life/>,document.getElementById("root"))
    </script>
</body>
</html>
  • 输出结果如下:
    在这里插入图片描述

1.4 写出定时器

//设置定时器
setInterval(()=>{
    //获取原来的状态
    let {opacity} = this.state;
    //每次减小0.1
    opacity -= 0.1;
    if(opacity<=0){
        opacity = 1;
    }
    //设置新的透明度
    //this.setState({opacity:opacity});
}, 200)

1.5 定时器放在组件的render()方法中(错误写法)

  • 如果定时器放到组件的render()方法中,会导致整个render()方法进入一个无限递归的状态;
  • 分析: 定时器放入render,render方法是在整个流程中执行 1+n次,每次更新状态就会执行一次render(),而且如果要改变透明度肯定要在类组件内定义state状态属性,每次属性的值改变就会调用一次组件的render()方法,所以是无限次的在调用定时器;
  • 而我们的定时器只是希望只在组件装载完成后,执行一次就行;
  • 所以要借用react的自身一个方法 componentDidMount(){} --组件已经装载的方法,
  • componentDidMount(){}方法和render方法一样直接写,所以修改后代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>案例引出组件的生命周期</title>

</head>
<body>
    <div id="root"></div>
    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <script type="text/babel">
        class Life extends  React.Component{
            state={opacity:1}

            death = ()=>{
                //卸载组件  unmount
                ReactDOM.unmountComponentAtNode(document.getElementById("root"));
            }

            componentDidMount(){
            	console.log("componentDidMount....");
                //设置定时器
                setInterval(()=>{
                    //获取原来的状态
                    let {opacity} = this.state;
                    //每次减小0.1
                    opacity -= 0.1;
                    if(opacity<=0){
                        opacity = 1;
                    }
                    //设置新的透明度
                    this.setState({opacity:opacity});
                }, 200)
            }

            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("root"))

    </script>


</body>
</html>
  • 那么render和componentDidMount哪个先执行?
    在这里插入图片描述
    • 肯定是render先执行;
    • 因为componentDidMount是组件装载完成才会执行的方法;

1.6 点击按钮,卸载组件

  • 把 death方法赋给 button按钮
  • 代码如下:
class Life extends  React.Component{
     state={opacity:1}

     death = ()=>{
         //卸载组件  unmount
         ReactDOM.unmountComponentAtNode(document.getElementById("root"));
     }
     //组件完成装载
     componentDidMount(){
         console.log("componentDidMount....");
         //设置定时器
         setInterval(()=>{
             //获取原来的状态
             let {opacity} = this.state;
             //每次减小0.1
             opacity -= 0.1;
             if(opacity<=0){
                 opacity = 1;
             }
             //设置新的透明度
             this.setState({opacity:opacity});
         }, 200)
     }
     //组件渲染
     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("root"))
  • 点击按钮,发现组件的确被卸载了
  • 如下图:
    在这里插入图片描述
  • 但是看控制台:
    在这里插入图片描述
  • 警告内容:Can’t perform a React state update on an unmounted component.
  • 翻译如下: 无法在卸载的组件上执行React状态更新。
  • 意思就是说组件卸载了,但是定时器还在执行组件的状态更新,所以才会报这个错误警告;
  • 所以我们 希望能够在组件被卸载之前,停止掉定时器;
    • 我们看 death方法,它的里面this是组件的实例对象;
    • 而componentDidMount方法中 this也是组件的实例对象;
    • 所以在componentDidMount方法中我们把定时器对象放到this中去,
    • 然后在death方法中通过this去控制定时器停止
案例引出组件的生命周期
<script type="text/babel">
    class Life extends  React.Component{
        state={opacity:1}

        death = ()=>{
            //清除定时器
            clearInterval(this.timer);
            //卸载组件  unmount
            ReactDOM.unmountComponentAtNode(document.getElementById("root"));
        }
        //组件完成装载
        componentDidMount(){
            console.log("componentDidMount....");
            //设置定时器,并把定时器对象放入this中去
            this.timer = setInterval(()=>{
                //获取原来的状态
                let {opacity} = this.state;
                //每次减小0.1
                opacity -= 0.1;
                if(opacity<=0){
                    opacity = 1;
                }
                //设置新的透明度
                this.setState({opacity:opacity});
            }, 200)
        }
        //组件渲染
        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("root"))

</script>
```
  • 输出结果如下: 没有报错
    在这里插入图片描述

  • 但是这是通过按钮点击事件触发,那么我希望在没有触发的情况下,单纯的只是在组件被卸载的时候,做一些事情,该如何做?

  • 也就是说希望能在组件卸载之前我们能做一些自己的操作;

1.7 componentWillUnmount组件被卸载前执行的函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>案例引出组件的生命周期</title>

</head>
<body>
    <div id="root"></div>
    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <script type="text/babel">
        class Life extends  React.Component{
            state={opacity:1}

            death = ()=>{
                console.log("button will click....");
                //卸载组件  unmount
                ReactDOM.unmountComponentAtNode(document.getElementById("root"));
                console.log("ReactDOM.unmountComponentAtNode....");
                console.log("button did click....");
            }
            //组件完成装载
            componentDidMount(){
                console.log("componentDidMount....");
                //设置定时器,并把定时器对象放入this中去
                this.timer = setInterval(()=>{
                    //获取原来的状态
                    let {opacity} = this.state;
                    //每次减小0.1
                    opacity -= 0.1;
                    if(opacity<=0){
                        opacity = 1;
                    }
                    //设置新的透明度
                    this.setState({opacity:opacity});
                }, 200)
            }

            //组件即将被卸载的时候
            componentWillUnmount(){
                console.log("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("root"))

    </script>


</body>
</html>
  • 输出结果如下:
    在这里插入图片描述
  • 隐隐约约能够感觉到react的生命周期,
  • 在某些时间点,react总会做一些事情
  • 这些特殊的时间点,我们也能够做一些自己的事情;

1.8 生命周期图示:

在这里插入图片描述

1.9 生命周期函数叫法

  • 生命周期函数;
  • 生命周期钩子函数;
  • 生命周期函数;
  • 生命周期钩子;

2. 组件的生命周期(旧)

2.1 组件的生命周期图(旧)

在这里插入图片描述

2.2 组件的生命周期使用

2.2.1 挂载时的生命周期

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo</title>
</head>
<body>
<!--1.准备好容器-->
<div id="root"></div>
<!--2.引入js文件-->
<script type="application/javascript" src="../js/react.development.js"></script>
<script type="application/javascript" src="../js/react-dom.development.js"></script>
<script type="application/javascript" src="../js/babel.min.js"></script>
<script type="application/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
    //3.1 创建组件
    class Count extends React.Component{
        //组件构造器
        constructor(props) {
            super(props);
            console.log("Count组件生命周期1 组件构造器-constructor");
            //初始化state
            this.state = {count:0};
        }

        //按钮点击回调 add函数
        add = ()=>{
            //获取原状态
            let count = this.state.count;
            //求和并更新state的值
            this.setState({count:count+1});
        }

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

        //组件将要挂载
        componentWillMount(){
            console.log("Count组件生命周期2 组件将要挂载-componentWillMount");
        }

        //组件已经挂载
        componentDidMount(){
            console.log("Count组件生命周期4 组件已经挂载-componentDidMount");
        }

        //渲染虚拟dom
        render(){
            console.log("Count组件生命周期3 渲染虚拟dom-render");
            return (
                <div>
                    <h2>点击后总和={this.state.count}</h2>
                    <button onClick={this.add}>点击+1</button>
                    <button onClick={this.death}>卸载组件</button>
                </div>
            );
        }

        //组件将要被卸载
        componentWillUnmount(){
            console.log("Count组件生命周期end 组件将要被卸载-componentWillUnmount");
        }

    }
    //3.2 渲染组件到页面
    ReactDOM.render(<Count/>, document.getElementById("root"))
</script>
</body>
</html>
  • 看下输出结果:
    • 初始化页面效果
      在这里插入图片描述
  • 点击+1 按钮点击
    在这里插入图片描述
  • 点击 卸载组件 按钮
    在这里插入图片描述
  • 可以看到Count组件的挂载时的生命周期如上图

2.2.2 父组件的render

  • 这里面又分三条线路,如下图:
    在这里插入图片描述
(1) 线路1 setState更新组件状态
(1.1)shouldComponentUpdat(){}组件是否render
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo</title>
</head>
<body>
<!--1.准备好容器-->
<div id="root"></div>
<!--2.引入js文件-->
<script type="application/javascript" src="../js/react.development.js"></script>
<script type="application/javascript" src="../js/react-dom.development.js"></script>
<script type="application/javascript" src="../js/babel.min.js"></script>
<script type="application/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
    //3.1 创建组件
    class Count extends React.Component{
        //组件构造器
        constructor(props) {
            super(props);
            console.log("Count组件生命周期1 组件构造器-constructor");
            //初始化state
            this.state = {count:0};
        }

        //按钮点击回调 add函数
        add = ()=>{
            //获取原状态
            let count = this.state.count;
            //求和并更新state的值
            this.setState({count:count+1});
        }

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

        //组件将要挂载
        componentWillMount(){
            console.log("Count组件生命周期2 组件将要挂载-componentWillMount");
        }

        //组件已经挂载
        componentDidMount(){
            console.log("Count组件生命周期4 组件已经挂载-componentDidMount");
        }

        //渲染虚拟dom
        render(){
            console.log("Count组件生命周期3 渲染虚拟dom-render");
            return (
                <div>
                    <h2>点击后总和={this.state.count}</h2>
                    <button onClick={this.add}>点击+1</button>
                    <button onClick={this.death}>卸载组件</button>
                </div>
            );
        }

        //组件将要被卸载
        componentWillUnmount(){
            console.log("Count组件生命周期end 组件将要被卸载-componentWillUnmount");
        }

        //组件是否要更新,有返回值
        //如果此方法不写,则react默认此方法返回值为true
        //该函数相当于一个开关的效果 true-state更新继续流程,false-state更新,不进行下一步,最终组件不会更新
        shouldComponentUpdate(){
            console.log("Count组件生命周期 组件是否要更新-shouldComponentUpdate");
            return true;
        }


    }
    //3.2 渲染组件到页面
    ReactDOM.render(<Count/>, document.getElementById("root"))
</script>
</body>
</html>
  • 返回true
    在这里插入图片描述
  • 返回false
    在这里插入图片描述
(1.2)componentWillUpdate(){}组件即将render
(1.3)componentDidUpdate(){}组件已经render
  • 举例如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo</title>
</head>
<body>
<!--1.准备好容器-->
<div id="root"></div>
<!--2.引入js文件-->
<script type="application/javascript" src="../js/react.development.js"></script>
<script type="application/javascript" src="../js/react-dom.development.js"></script>
<script type="application/javascript" src="../js/babel.min.js"></script>
<script type="application/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
    //3.1 创建组件
    class Count extends React.Component{
        //组件构造器
        constructor(props) {
            super(props);
            console.log("Count组件生命周期1 组件构造器-constructor");
            //初始化state
            this.state = {count:0};
        }

        //按钮点击回调 add函数
        add = ()=>{
            //获取原状态
            let count = this.state.count;
            //求和并更新state的值
            this.setState({count:count+1});
        }

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

        //组件将要挂载
        componentWillMount(){
            console.log("Count组件生命周期2 组件将要挂载-componentWillMount");
        }

        //组件已经挂载
        componentDidMount(){
            console.log("Count组件生命周期4 组件已经挂载-componentDidMount");
        }

        //渲染虚拟dom
        render(){
            console.log("Count组件生命周期3 渲染虚拟dom-render");
            return (
                <div>
                    <h2>点击后总和={this.state.count}</h2>
                    <button onClick={this.add}>点击+1</button>
                    <button onClick={this.death}>卸载组件</button>
                </div>
            );
        }

        //组件将要被卸载
        componentWillUnmount(){
            console.log("Count组件生命周期end 组件将要被卸载-componentWillUnmount");
        }

        //组件是否要更新,有返回值
        //如果此方法不写,则react默认此方法返回值为true
        //该函数相当于一个开关的效果 true-state更新继续流程,false-state更新,不进行下一步,最终组件不会更新
        shouldComponentUpdate(){
            console.log("Count组件生命周期 组件是否要render-shouldComponentUpdate");
            return true;
        }

        //组件即将更新
        componentWillUpdate(){
            console.log("Count组件生命周期 组件即将render-componentWillUpdate");
        }

        //组件已经更新
        componentDidUpdate(){
            console.log("Count组件生命周期 组件已经render-componentDidUpdate");
        }

    }
    //3.2 渲染组件到页面
    ReactDOM.render(<Count/>, document.getElementById("root"))
</script>
</body>
</html>
  • 输出结果
    在这里插入图片描述
  • 点击 卸载组件 按钮
    在这里插入图片描述
(2)线路2 forceUpdate 强制更新
  • 不想更新状态state,但想更新组件,执行render
  • 绕过shouldComponentUpdate 开关,直接更新
  • 举例如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo</title>
</head>
<body>
<!--1.准备好容器-->
<div id="root"></div>
<!--2.引入js文件-->
<script type="application/javascript" src="../js/react.development.js"></script>
<script type="application/javascript" src="../js/react-dom.development.js"></script>
<script type="application/javascript" src="../js/babel.min.js"></script>
<script type="application/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
    //3.1 创建组件
    class Count extends React.Component{
        //组件构造器
        constructor(props) {
            super(props);
            console.log("Count组件生命周期1 组件构造器-constructor");
            //初始化state
            this.state = {count:0};
        }

        //按钮点击回调 add函数
        add = ()=>{
            //获取原状态
            let count = this.state.count;
            //求和并更新state的值
            this.setState({count:count+1});
            console.log(this.state.count);
        }

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

        //强制更新
        force = ()=>{
            console.log("Count组件生命周期 组件强制更新-forceUpdate");
            this.forceUpdate()
        }

        //组件将要挂载
        componentWillMount(){
            console.log("Count组件生命周期2 组件将要挂载-componentWillMount");
        }

        //组件已经挂载
        componentDidMount(){
            console.log("Count组件生命周期4 组件已经挂载-componentDidMount");
        }

        //渲染虚拟dom
        render(){
            console.log("Count组件生命周期3 渲染虚拟dom-render");
            return (
                <div>
                    <h2>点击后总和={this.state.count}</h2>
                    <button onClick={this.add}>点击+1</button>
                    <button onClick={this.death}>卸载组件</button>
                    <button onClick={this.force}>不改变state强制更新forceUpdate</button>
                </div>
            );
        }

        //组件将要被卸载
        componentWillUnmount(){
            console.log("Count组件生命周期end 组件将要被卸载-componentWillUnmount");
        }

        //组件是否要更新,有返回值
        //如果此方法不写,则react默认此方法返回值为true
        //该函数相当于一个开关的效果 true-state更新继续流程,false-state更新,不进行下一步,最终组件不会更新
        shouldComponentUpdate(){
            console.log("Count组件生命周期 组件是否要render-shouldComponentUpdate");
            return true;
        }

        //组件即将更新
        componentWillUpdate(){
            console.log("Count组件生命周期 组件即将render-componentWillUpdate");
        }

        //组件已经更新
        componentDidUpdate(){
            console.log("Count组件生命周期 组件已经render-componentDidUpdate");
        }

    }
    //3.2 渲染组件到页面
    ReactDOM.render(<Count/>, document.getElementById("root"));
</script>
</body>
</html>

在这里插入图片描述

(3)父组件render时,子组件相关钩子方法
  • componentWillReceiveProps(){} 子组件接收父组件Props参数
  • 示例代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>父组件A  子组件B</title>
</head>
<body>
<!--1.准备好容器-->
<div id="root"></div>
<!--2.引入js文件-->
<script type="application/javascript" src="../js/react.development.js"></script>
<script type="application/javascript" src="../js/react-dom.development.js"></script>
<script type="application/javascript" src="../js/babel.min.js"></script>
<script type="application/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
    //3.1 创建组件
    class A extends React.Component{
        state = {carName:"奔驰"};
        changeCar = ()=>{
            this.setState({carName:"奥拓"});
        }
        render(){
            return (
                <div>
                    <h2>我是A组件,我的车为:{this.state.carName}</h2>
                    <button onClick={this.changeCar}>A中点击按钮</button>
                    <B carName={this.state.carName}/>
                </div>
            );
        }

    }

    //子组件B
    class B extends React.Component{
        render(){
            return (
                <div>
                    <h2>我是B组件,接收到的车为:{this.props.carName}</h2>
                </div>
            );
        }

        //组件是否接收新的Props
        componentWillReceiveProps(props){
            console.log("组件B--componentWillReceivePros",props);
        }
    }

    //3.2 渲染组件到页面
    ReactDOM.render(<A/>, document.getElementById("root"))
</script>
</body>
</html>
  • 页面初始化结果如下:
    在这里插入图片描述
  • 点击按钮,发现控制台打印了
    在这里插入图片描述
  • 注意:componentWillReceiveProps这个方法有个坑:
    • 如果是页面初始化,这个方法在组件B中不执行;
    • 当组件Arender的时候,组件B的 componentWillReceiveProps 才会执行,后面是组件A每次render的时候都会执行;
  • 也就是说组件A执行render的方法的时候,作为从组件A中接收props参数的组件B才会执行下面一系列方法,
    在这里插入图片描述

3. 组件的生命周期(旧)总结:

3.1组件生命周期(旧)分阶段

(1.) 初始化阶段

  • 由ReactDOM.render()方法触发初次渲染,依次执行下面的方法
    • constructor()
    • componentWillMount()
    • render()
    • componentDidMount() -----常用,初始化操作,开启定时器、网络请求、订阅消息

(2.)更新阶段

  • 情况① 由父组件render触发
  • 情况② 组件自身state状态改变了
    • shouldComponentUpdate()
    • componentWillUpdate()
    • render() -----常用,用的最多
    • componentDidUpdate()

(3.)卸载阶段

  • ReactDOM.unmountComponentNode()触发
    • componentWillUnmount() -----常用,收尾操作,关闭定时器、取消消息订阅

4. 组件的生命周期(新)

4.1 生命周期(新)图

在这里插入图片描述

4.2 生命周期(新)3个钩子函数改名

  • 在原来的名字前面加上前缀 UNSAFE_
  • 原来的钩子函数还能用,但是控制台会有警告
  • 在未来react18.x版本的时候,只有带上前缀 UNSAFE_ 的函数才能使用;
  • 官方说明地址
  • 三个函数分别是:
    • componentWillMount ==> UNSAFE_componentWillMount 组件将要挂载
    • componentWillReceiveProps ==> UNSAFE_componentWillReceiveProps 子组件接收父组件的新Props参数
    • componentWillUpdate ==> UNSAFE_componentWillUpdate 组件将要更新
      在这里插入图片描述
  • 这3个钩子函数更名原因:
react正在开发异步渲染功能:
我们得到最重要的经验是,过时的组件生命周期往往会带来不安全的编码实践,具体函数如下:
componentWillMount
componentWillReceiveProps
componentWillUpdate
这些生命周期方法经常被误解和滥用;此外,我们预计,在异步渲染中,它们潜在的误用问题可能更大。我们将在即将发布的版本中为这些生命周期添加 “UNSAFE_” 前缀。(这里的 “unsafe” 不是指安全性,而是表示使用这些生命周期的代码在 React 的未来版本中更有可能出现 bug,尤其是在启用异步渲染之后。)

因此这种变化将是逐步的。我们目前的计划是:

16.3:为不安全的生命周期引入别名,UNSAFE_componentWillMount、UNSAFE_componentWillReceiveProps 和 UNSAFE_componentWillUpdate。(旧的生命周期名称和新的别名都可以在此版本中使用。)
未来 16.x 版本:为 componentWillMount、componentWillReceiveProps 和 componentWillUpdate 启用废弃告警。(旧的生命周期名称和新的别名都将在这个版本中工作,但是旧的名称在开发模式下会产生一个警告。)
17.0:删除 componentWillMount、componentWillReceiveProps 和 componentWillUpdate。(在此版本之后,只有新的 “UNSAFE_” 生命周期名称可以使用。)

4.3 生命周期(新)新增2个钩子函数

  • 生命周期(旧)中3个钩子函数会在后期版本逐渐弃用,但是可以更名加前缀 UNSAFE_ 继续使用
  • 新增2个钩子函数,基本不怎么使用
    • getDerivedStateFromProps
    • getSnapshotBeforeUpdate

4.3.1 getDerivedStateFromProps(props,state)

  • 需要引入react17.x
  • 示例代码:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>4-组件生命周期(新)</title>
</head>
<body>
<!--1.准备好容器-->
<div id="root"></div>
<!--2.引入js文件-->
<script type="application/javascript" src="../js/17.0.1/react.development.js"></script>
<script type="application/javascript" src="../js/17.0.1/react-dom.development.js"></script>
<script type="application/javascript" src="../js/17.0.1/babel.min.js"></script>
<script type="application/javascript" src="../js/17.0.1/prop-types.js"></script>
<script type="text/babel">
    //3.1 创建组件
    class Count extends React.Component{
        //组件构造器
        constructor(props) {
            super(props);
            console.log("Count组件生命周期1 组件构造器-constructor");
            //初始化state
            this.state = {count:0};
        }

        getDerivedStateFromProps(){
            console.log("生命周期 新 getDerivedStateFromProps");
        }

        //按钮点击回调 add函数
        add = ()=>{
            //获取原状态
            let count = this.state.count;
            //求和并更新state的值
            this.setState({count:count+1});
            console.log(this.state.count);
        }

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

        //强制更新
        force = ()=>{
            console.log("Count组件生命周期 组件强制更新-forceUpdate");
            this.forceUpdate()
        }


        //组件已经挂载
        componentDidMount(){
            console.log("Count组件生命周期4 组件已经挂载-componentDidMount");
        }

        //渲染虚拟dom
        render(){
            console.log("Count组件生命周期3 渲染虚拟dom-render");
            return (
                <div>
                    <h2>点击后总和={this.state.count}</h2>
                    <button onClick={this.add}>点击+1</button>
                    <button onClick={this.death}>卸载组件</button>
                    <button onClick={this.force}>不改变state强制更新forceUpdate</button>
                </div>
            );
        }

        //组件将要被卸载
        componentWillUnmount(){
            console.log("Count组件生命周期end 组件将要被卸载-componentWillUnmount");
        }

        //组件已经更新
        componentDidUpdate(){
            console.log("Count组件生命周期 组件已经render-componentDidUpdate");
        }

    }
    //3.2 渲染组件到页面
    ReactDOM.render(<Count/>, document.getElementById("root"));
</script>
</body>
</html>
  • 页面初始化报错:
    在这里插入图片描述
  • 说明 getDerivedStateFromProps 方法不属于组件实例的,而是属于组件类的原型的
  • 修改代码加上static定义方法
static getDerivedStateFromProps(){
	console.log("生命周期 新 getDerivedStateFromProps");
}
  • 页面初始化结果如下:
    在这里插入图片描述
  • 必须有返回值:
    • stateObject
    • null
  • 如果返回 null
static getDerivedStateFromProps(){
	console.log("生命周期 新 getDerivedStateFromProps");
	return null;
}
  • 页面初始化结果如下:
    在这里插入图片描述
  • 如果返回 stateObject ,代码修改如下
static getDerivedStateFromProps(){
	console.log("生命周期 新 getDerivedStateFromProps");
	return {count:99};
}
  • 页面初始化结果如下:
    在这里插入图片描述
  • 点击 +1按钮,页面效果如下:
    在这里插入图片描述
  • 点击按钮 state中 count不在+1,count的值永远是99
  • 也就是说 getDerivedStateFromProps方法的返回对象的属性值影响state中同名的属性值,并且会保持不变;
  • getDerivedStateFromProps (props) 接收 props参数
	//修改地方1
	static getDerivedStateFromProps(props){
         console.log("生命周期 新 getDerivedStateFromProps   props=",props);
            //直接返回接收的参数props
            return props;
    }
	//修改地方2
    ReactDOM.render(<Count count="199"/>, document.getElementById("root"));
  • 页面初始化结果如下:
    在这里插入图片描述
  • 总结:这个方法使state值由props来决定
  • 官方参考 getDerivedStateFromProps
  • getDerivedFromProps(props,state) 可以接收两个参数 props state
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>4-组件生命周期(新)</title>
</head>
<body>
<!--1.准备好容器-->
<div id="root"></div>
<!--2.引入js文件-->
<script type="application/javascript" src="../js/17.0.1/react.development.js"></script>
<script type="application/javascript" src="../js/17.0.1/react-dom.development.js"></script>
<script type="application/javascript" src="../js/17.0.1/babel.min.js"></script>
<script type="application/javascript" src="../js/17.0.1/prop-types.js"></script>
<script type="text/babel">
    //3.1 创建组件
    class Count extends React.Component{
        //组件构造器
        constructor(props) {
            super(props);
            console.log("Count组件生命周期1 组件构造器-constructor");
            //初始化state
            this.state = {count:1};
        }

        static getDerivedStateFromProps(props,state){
            console.log("生命周期 新 getDerivedStateFromProps   props=",props);
            console.log("生命周期 新 getDerivedStateFromProps   state=",state);
            //直接把props返回
            return {count:props.count+state.count};
        }

        //按钮点击回调 add函数
        add = ()=>{
            //获取原状态
            let count = this.state.count;
            //求和并更新state的值
            this.setState({count:count+1});
            console.log(this.state.count);
        }

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

        //强制更新
        force = ()=>{
            console.log("Count组件生命周期 组件强制更新-forceUpdate");
            this.forceUpdate()
        }


        //组件已经挂载
        componentDidMount(){
            console.log("Count组件生命周期4 组件已经挂载-componentDidMount");
        }

        //渲染虚拟dom
        render(){
            console.log("Count组件生命周期3 渲染虚拟dom-render");
            return (
                <div>
                    <h2>点击后总和={this.state.count}</h2>
                    <button onClick={this.add}>点击+1</button>
                    <button onClick={this.death}>卸载组件</button>
                    <button onClick={this.force}>不改变state强制更新forceUpdate</button>
                </div>
            );
        }

        //组件将要被卸载
        componentWillUnmount(){
            console.log("Count组件生命周期end 组件将要被卸载-componentWillUnmount");
        }

        //组件已经更新
        componentDidUpdate(){
            console.log("Count组件生命周期 组件已经render-componentDidUpdate");
        }

    }
    //3.2 渲染组件到页面
    ReactDOM.render(<Count count={199}/>, document.getElementById("root"));
</script>
</body>
</html>
  • 页面初始化结果如下:
    在这里插入图片描述

4.3.2 getSnapshotBeforeUpdate

  • 示例代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>4-组件生命周期(新)</title>
</head>
<body>
<!--1.准备好容器-->
<div id="root"></div>
<!--2.引入js文件-->
<script type="application/javascript" src="../js/17.0.1/react.development.js"></script>
<script type="application/javascript" src="../js/17.0.1/react-dom.development.js"></script>
<script type="application/javascript" src="../js/17.0.1/babel.min.js"></script>
<script type="application/javascript" src="../js/17.0.1/prop-types.js"></script>
<script type="text/babel">
    //3.1 创建组件
    class Count extends React.Component{
        //组件构造器
        constructor(props) {
            super(props);
            console.log("Count组件生命周期1 组件构造器-constructor");
            //初始化state
            this.state = {count:0};
        }

        //让这个方法返回null
        static getDerivedStateFromProps(props,state){
            console.log("生命周期 新 getDerivedStateFromProps   props=",props);
            console.log("生命周期 新 getDerivedStateFromProps   state=",state);
            //直接把props返回
            return null
        }

        getSnapshotBeforeUpdate(){
            console.log("生命周期 新 getSnapshotBeforeUpdate");
        }

        //按钮点击回调 add函数
        add = ()=>{
            //获取原状态
            let count = this.state.count;
            //求和并更新state的值
            this.setState({count:count+1});
            console.log(this.state.count);
        }

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

        //强制更新
        force = ()=>{
            console.log("Count组件生命周期 组件强制更新-forceUpdate");
            this.forceUpdate()
        }


        //组件已经挂载
        componentDidMount(){
            console.log("Count组件生命周期4 组件已经挂载-componentDidMount");
        }

        //渲染虚拟dom
        render(){
            console.log("Count组件生命周期3 渲染虚拟dom-render");
            return (
                <div>
                    <h2>点击后总和={this.state.count}</h2>
                    <button onClick={this.add}>点击+1</button>
                    <button onClick={this.death}>卸载组件</button>
                    <button onClick={this.force}>不改变state强制更新forceUpdate</button>
                </div>
            );
        }

        //组件将要被卸载
        componentWillUnmount(){
            console.log("Count组件生命周期end 组件将要被卸载-componentWillUnmount");
        }

        //组件已经更新
        componentDidUpdate(){
            console.log("Count组件生命周期 组件已经render-componentDidUpdate");
        }

    }
    //3.2 渲染组件到页面
    ReactDOM.render(<Count count={199}/>, document.getElementById("root"));
</script>
</body>
</html>
  • 页面初始化结果如下:
    在这里插入图片描述
  • 这个方法必须有返回值
    • null
    • snapshot value 快照值 (可以是任意的值)
  • 给 getSnapshotBeforeUpdate 方法添加返回值 null
getSnapshotBeforeUpdate(){
    console.log("生命周期 新 getSnapshotBeforeUpdate");
    return null;
}
  • 输出结果如下:
    在这里插入图片描述
  • 给 getSnapshotBeforeUpdate 方法添加返回值 snapshot value 快照值
		//修改位置 1
		getSnapshotBeforeUpdate(prevProps, prevState){
            console.log("生命周期 新 getSnapshotBeforeUpdate");
            console.log("生命周期 新 getSnapshotBeforeUpdate   prevProps=",prevProps);
            console.log("生命周期 新 getSnapshotBeforeUpdate   prevState=",prevState);
            return "qq28129019";
        }
        // 修改位置  2
        componentDidUpdate(prevProps,prevState,snapshot){
            console.log("Count组件生命周期 组件已经render-componentDidUpdate");
            console.log("生命周期  新 componentDidUpdate  prevProps=",prevProps);
            console.log("生命周期  新 componentDidUpdate  prevState=",prevState);
            console.log("生命周期  新 componentDidUpdate  snapshot=",snapshot);
        }
  • 输出结果如下:
    在这里插入图片描述

  • 也就是说 getSnapshotBeforeUpdate()的返回值传递给 componentDidUpdate() 方法

  • 完整代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>4-组件生命周期(新)</title>
</head>
<body>
<!--1.准备好容器-->
<div id="root"></div>
<!--2.引入js文件-->
<script type="application/javascript" src="../js/17.0.1/react.development.js"></script>
<script type="application/javascript" src="../js/17.0.1/react-dom.development.js"></script>
<script type="application/javascript" src="../js/17.0.1/babel.min.js"></script>
<script type="application/javascript" src="../js/17.0.1/prop-types.js"></script>
<script type="text/babel">
    //3.1 创建组件
    class Count extends React.Component{
        //组件构造器
        constructor(props) {
            super(props);
            console.log("Count组件生命周期1 组件构造器-constructor");
            //初始化state
            this.state = {count:0};
        }

        //让这个方法返回null
        static getDerivedStateFromProps(props,state){
            console.log("生命周期 新 getDerivedStateFromProps   props=",props);
            console.log("生命周期 新 getDerivedStateFromProps   state=",state);
            //直接把props返回
            return null
        }


        getSnapshotBeforeUpdate(prevProps, prevState){
            console.log("生命周期 新 getSnapshotBeforeUpdate");
            console.log("生命周期 新 getSnapshotBeforeUpdate   prevProps=",prevProps);
            console.log("生命周期 新 getSnapshotBeforeUpdate   prevState=",prevState);
            return "qq28129019";
        }

        //按钮点击回调 add函数
        add = ()=>{
            //获取原状态
            let count = this.state.count;
            //求和并更新state的值
            this.setState({count:count+1});
            console.log(this.state.count);
        }

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

        //强制更新
        force = ()=>{
            console.log("Count组件生命周期 组件强制更新-forceUpdate");
            this.forceUpdate()
        }


        //组件已经挂载
        componentDidMount(){
            console.log("Count组件生命周期4 组件已经挂载-componentDidMount");
        }

        //渲染虚拟dom
        render(){
            console.log("Count组件生命周期3 渲染虚拟dom-render");
            return (
                <div>
                    <h2>点击后总和={this.state.count}</h2>
                    <button onClick={this.add}>点击+1</button>
                    <button onClick={this.death}>卸载组件</button>
                    <button onClick={this.force}>不改变state强制更新forceUpdate</button>
                </div>
            );
        }

        //组件将要被卸载
        componentWillUnmount(){
            console.log("Count组件生命周期end 组件将要被卸载-componentWillUnmount");
        }

        //组件已经更新
        componentDidUpdate(prevProps,prevState,snapshot){
            console.log("Count组件生命周期 组件已经render-componentDidUpdate");
            console.log("生命周期  新 componentDidUpdate  prevProps=",prevProps);
            console.log("生命周期  新 componentDidUpdate  prevState=",prevState);
            console.log("生命周期  新 componentDidUpdate  snapshot=",snapshot);
        }

    }
    //3.2 渲染组件到页面
    ReactDOM.render(<Count count={199}/>, document.getElementById("root"));
</script>
</body>
</html>

4.4 新旧生命周期对比图

在这里插入图片描述

4.6 生命周期(新)新增钩子函数的示例:

  • 初始化代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>5-生命周期新钩子方法的使用示例</title>
    <style>
        .list{
            width:200px;
            height:150px;
            background-color: aquamarine;
            overflow: auto;
        }
        .news{
            height: 30px;
        }
    </style>
</head>
<body>
<!--1.准备好容器-->
<div id="root"></div>
<!--2.引入js文件-->
<script type="application/javascript" src="../js/17.0.1/react.development.js"></script>
<script type="application/javascript" src="../js/17.0.1/react-dom.development.js"></script>
<script type="application/javascript" src="../js/17.0.1/babel.min.js"></script>
<script type="application/javascript" src="../js/17.0.1/prop-types.js"></script>
<script type="text/babel">
    class NewsList extends React.Component{
        render(){
            return (
                <div className="list">
                    <div className="news">新闻7</div>
                    <div className="news">新闻6</div>
                    <div className="news">新闻5</div>
                    <div className="news">新闻4</div>
                    <div className="news">新闻3</div>
                    <div className="news">新闻2</div>
                    <div className="news">新闻1</div>
                </div>
            );
        }
    }
    ReactDOM.render(<NewsList/>,document.getElementById("root"));
</script>
</body>
</html>
  • 页面加载效果如下:
    在这里插入图片描述
  • 实现新增新闻的同时,界面显示的新闻不会自动下移:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>5-生命周期新钩子方法的使用示例</title>
    <style>
        .list{
            width:200px;
            height:150px;
            background-color: aquamarine;
            overflow: auto;
        }
        .news{
            height: 30px;
        }
    </style>
</head>
<body>
<!--1.准备好容器-->
<div id="root"></div>
<!--2.引入js文件-->
<script type="application/javascript" src="../js/17.0.1/react.development.js"></script>
<script type="application/javascript" src="../js/17.0.1/react-dom.development.js"></script>
<script type="application/javascript" src="../js/17.0.1/babel.min.js"></script>
<script type="application/javascript" src="../js/17.0.1/prop-types.js"></script>
<script type="text/babel">
    class NewsList extends React.Component{

        state = {newsArr:[]};

        componentDidMount(){
            setInterval(()=>{
                //获取原状态
                const {newsArr} = this.state;
                const news = "新闻"+(newsArr.length+1);
                this.setState({newsArr:[news,...newsArr]});
            }, 1000);
        }

        render(){
            return (
                <div className="list" ref="list">
                    {
                        this.state.newsArr.map((n,index)=>{
                            return <div key={index} className="news">{n}</div>
                        })
                    }
                </div>
            );
        }

        getSnapshotBeforeUpdate(){
            return this.refs.list.scrollHeight;
        }

        componentDidUpdate(prevProps,prevState,snapshot){
            this.refs.list.scrollTop += this.refs.list.scrollHeight-snapshot;
        }
    }
    ReactDOM.render(<NewsList/>,document.getElementById("root"));
</script>
</body>
</html>
  • 页面加载后效果:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 新的新闻不断生成,但是页面并没有随着新闻生成而让最先生成的新闻顶下去

5.组件生命周期(新) 总结

5.1 生命周期的三个阶段

  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()
  3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
    1. componentWillUnmount()

5.2 重要的勾子

  1. render:初始化渲染或更新渲染调用
  2. componentDidMount:开启监听, 发送ajax请求
  3. componentWillUnmount:做一些收尾工作, 如: 清理定时器

5.3 即将废弃的勾子

  1. componentWillMount
  2. componentWillReceiveProps
  3. componentWillUpdate
    注意:现在使用会出现警告,下一个大版本需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

神奇洋葱头

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值