React 组件的生命周期

1. 组件的生命周期

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

1) 引出生命周期

    //生命周期回调函数 <=> 生命周期钩子函数 <=> 生命周期函数 <=> 生命周期钩子
   //render调用的时机是2个:初始化渲染、状态更新之后
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset = "UTF-8">
    <meta name = "viewport" content="width=device-width, initial-scale=1.0">
    <title>1_引出生命周期</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">
    //创建组件
    //生命周期回调函数 <=> 生命周期钩子函数 <=> 生命周期函数 <=> 生命周期钩子
    class Life extends React.Component{

        state = {opacity:1}

        death = () => {
            // //清除定时器
            // clearInterval(this.timer)
            //卸载组件
            ReactDOM.unmountComponentAtNode(document.getElementById('test'))
        }
        
        //组件挂载完毕调用
        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调用的时机是2个:初始化渲染、状态更新之后
        render(){
            return(
                <div>
                <h2 style={{opacity:this.state.opacity}}>React学不会怎么办?</h2>
                <button onClick={this.death}>不活了</button>
                </div>
            )
        }
    }

    //渲染组件
    ReactDOM.render(<Life/>,document.getElementById('test'))
</script>
</body>
</html>

2)组件生命周期的三个阶段(旧)

在这里插入图片描述

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()
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset = "UTF-8">
    <meta name = "viewport" content="width=device-width, initial-scale=1.0">
    <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');
        }

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

        //控制组件更新的阀门
        shouldComponentUpdate(){
            console.log('Count-shouldComponentUpdate');
            return false
        }

        //组件将要更新的钩子
        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:'benz'}

        changeCar = () => {
            this.setState({carName:'auto'})
        }
        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(){
            console.log('B-componentWillReceiveProps');
        }

        //控制组件更新的阀门
        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>
</body>
</html>

3) 组件的生命周期(新)
在这里插入图片描述

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() ===> 常用**
            一般在这个钩子中做一些收尾的事。例如:关闭定时器,取消订阅消息,
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset = "UTF-8">
    <meta name = "viewport" content="width=device-width, initial-scale=1.0">
    <title>3_react生命周期(新)</title>
</head>
<body>
<!-- 准备好一个“容器” -->
<div id = "test"></div>

<!-- 引入react核心库 -->
<script type="text/javascript" src="../js/17/react.development.js"> </script>
<!-- 引入react-dom 用于支持react操作DOM -->
<script type="text/javascript" src="../js/17/react-dom.development.js"></script>
<!-- 引入babel,用于将jsx转化为js -->
<script type="text/javascript" src="../js/17/babel.min.js"></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})
        }

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

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

        //从props得到一个衍生的状态,使用场景及其罕见
        //若state的值在任何时候都取决于props,那么可以使用getDerivedStateFromProps
        static getDerivedStateFromProps(props,state){
            console.log('getDrivedStateFromProps',props,state);
            return null
        }

        //在更新之前获取快照,此用法并不常见
        getSnapshotBeforeUpdate(){
            console.log('getSnapshotBeforeUpdate');
            return 'atguigu'
        }

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

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

        //控制组件更新的阀门
        shouldComponentUpdate(){
            console.log('Count-shouldComponentUpdate');
            return true
        }

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



        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 count={199}/>,document.getElementById('test'))
</script>
</body>
</html>

4) 重要的钩子与即将废弃的钩子

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


即将废弃的钩子
	1.	componentWillMount
	2.	componentWillReceiveProps
	3.	componentWillUpdate

现在使用会出现警告,下一个大版本需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用。

5) getSnapshotBeforeUpdate的使用场景

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset = "UTF-8">
    <meta name = "viewport" content="width=device-width, initial-scale=1.0">
    <title>4_getSnapshotBeforeUpdate的使用场景</title>
    <style>
        .list{
            width:200px;
            height: 150px;
            background-color: skyblue;
            overflow: auto;
        }
        .news{
            height: 30px;
        }
    </style>
</head>


<body>
<!-- 准备好一个“容器” -->
<div id = "test"></div>

<!-- 引入react核心库 -->
<script type="text/javascript" src="../js/17/react.development.js"> </script>
<!-- 引入react-dom 用于支持react操作DOM -->
<script type="text/javascript" src="../js/17/react-dom.development.js"></script>
<!-- 引入babel,用于将jsx转化为js -->
<script type="text/javascript" src="../js/17/babel.min.js"></script>

<script type="text/babel">
    class NewList extends React.Component{

        state = {newsArr:[]}

        componentDidMount(){
            setInterval(() => {
                //获取状态
                const{newsArr} = this.state
                //模拟一条新闻
                const news = '新闻'+(newsArr.length+1)
                //更新状态
                this.setState({newsArr:[news,...newsArr]})
            },1000)
        }

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

        componentDidUpdate(preProps,preState,height){
            this.refs.list.scrollTop += this.refs.list.scrollHeight - height
        }

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

    ReactDOM.render(<NewList/>,document.getElementById('test'))
</script>
</body>
</html>

6) 虚拟DOM与DOM Diffing算法

基本原理图
在这里插入图片描述
a. 验证Diffing算法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset = "UTF-8">
    <meta name = "viewport" content="width=device-width, initial-scale=1.0">
    <title>1_验证Diffing算法</title>
</head>
<body>
<!-- 准备好一个“容器” -->
<div id = "test"></div>

<!-- 引入react核心库 -->
<script type="text/javascript" src="../js/17/react.development.js"> </script>
<!-- 引入react-dom 用于支持react操作DOM -->
<script type="text/javascript" src="../js/17/react-dom.development.js"></script>
<!-- 引入babel,用于将jsx转化为js -->
<script type="text/javascript" src="../js/17/babel.min.js"></script>

<script type="text/babel">
    class Time extends React.Component{
        state = {date:new Date()}

        componentDidMount(){
            setInterval(() => {
                this.setState({
                    date:new Date()
                })
            ,1000})
        }

        render(){
            return(
                <div>
                <h1>Hello</h1>
                <input type="text" />
                <span>
                现在是:{this.state.date.toTimeString()}
                <input type="text" />
                </span>
                </div>
            )
        }
    }

    ReactDOM.render(<Time/>,document.getElementById('test'))
</script>
</body>
</html>

b. key的作用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset = "UTF-8">
    <meta name = "viewport" content="width=device-width, initial-scale=1.0">
    <title>2_key的作用</title>
</head>
<body>
<!-- 准备好一个“容器” -->
<div id = "test"></div>

<!-- 引入react核心库 -->
<script type="text/javascript" src="../js/17/react.development.js"> </script>
<!-- 引入react-dom 用于支持react操作DOM -->
<script type="text/javascript" src="../js/17/react-dom.development.js"></script>
<!-- 引入babel,用于将jsx转化为js -->
<script type="text/javascript" src="../js/17/babel.min.js"></script>

<script type="text/babel">


    class Person extends React.Component{

        state = {
            persons:[
                {id:1,name:'tim',age:11},
                {id:2,name:'tom',age:1},
            ]
        }

        add = () => {
            const{persons} = this.state
            const p = {id:persons.length+1,name:'小王',age:20}
            this.setState({persons:[p,...persons]})
        }   

        render(){
            return(
               <div>
               <h2>展示人员信息</h2>
               <button onClick={this.add}>添加一个小王</button>
               <h3>使用index(索引值)作为key</h3>
               <ul>
                {
                    this.state.persons.map((personObj,index) => {
                    return <li key={index}>{personObj.name}----{personObj.age} <input type="text"/> </li>
                    })
                }
                </ul>
                

                <hr/>
                <hr/>

                <h3>使用id(数据的唯一标识)作为key</h3>
                <ul>
                {this.state.persons.map((personObj) => {
                    return <li key={personObj.id}>{personObj.name}----{personObj.age} <input type="text"/> </li>
                })}
                </ul>
                </div>
            )
        }
    }
    ReactDOM.render(<Person/>,document.getElementById('test'))

</script>
</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值