• react中函数组件和class组件的区别


    函数组件和class组件

    函数组件

    函数组件是无状态的,每一次更新数据都会重新调用函数,生成新的函数执行上下文

    所以在hook出现之前,函数组件大都只能用来当作纯展示组件,因为它内部没有存储状态(state),没有生命周期,并且逻辑不能复用

    编写函数组件称为函数式编程

    class组件

    class组件是基于es6中的类的,编写class组件称为面向对象编程

    class组件有状态,有自己的生命周期

    在hook出现之前,逻辑比较复杂或者需要依赖状态的组件都采用class组件的形式

    所以他们的本质区别是什么?

    直接看代码

    class组件

    class Index extends React.Component{
        constructor(props){
            super(props)
            this.state={
                number:0
            }
        }
        handerClick=()=>{
           for(let i = 0 ;i<5;i++){
               setTimeout(()=>{
                   this.setState({ number:this.state.number+1 })
                   console.log(this.state.number)
               },1000)
           }
        }
    
        render(){
            return 
    } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    函数组件

    function Index(){
        const [ num ,setNumber ] = React.useState(0)
        const handerClick=()=>{
            for(let i=0; i<5;i++ ){
               setTimeout(() => {
                    setNumber(num+1)
                    console.log(num)
               }, 1000)
            }
        }
        return 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    上面两个代码片段会分别打印什么结果?

    第一个例子: 0 0 0 0 0

    第二个例子: 0 0 0 0 0


    先来解释第一个例子

    第一个例子是用class组件的形式

    初始化一个名为number的state,初始值为0

    点击按钮执行handerClick方法,触发number的更新,在更新函数中使用了循环递增的方式,并且加了1000ms的延时

    在react18版本中,react对状态更新做了自动批处理,也就是说在很短时间内多次更新同一个状态,react只会以更新前的state值为基础进行状态更新

    this.state = {
        number: 0
    }
    this.setState({number:this.state.number+1})
    this.setState({number:this.state.number+1})
    this.setState({number:this.state.number+1})
    //此时number的值:1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    上述代码相当于执行了三次

    this.setState({number:0 +1})

    因为在短时间内this.state.number的值始终为0!(归根结底还是因为setState是异步的)

    所以我们就能理解了

    短时间内打印number 始终为0

    但是我们假设react没有对状态做自动分批处理

    输出结果会是怎样?

    答案是: 1 2 3 4 5

    归根结底还是state被保存起来了,每次setState都会以上一次state为基础进行递增

    不论react对状态进行了什么处理,我们要知道的是,class组件是有状态的,他的状态会在组件生命周期中一直保存


    我们再来看第二个例子:函数组件

    这个对熟悉闭包的人应该比较容易理解

    在for循环中使用setTimeOut回调会产生闭包,闭包中的num会指向原函数作用域中的num,也就是0

    所以我们每次执行setNumber(num + 1)实际上都是执行setNumber(0 + 1),执行console.log(num);实际都是执行console.log(0)

    在循环结束后 num的值会变成1,因为setNumber(0 + 1)执行后将num置为1


    我们梳理一下执行一次setNumber的流程:

    1. 执行setNumber后,会导致组件function重新,所有语句会被重新调用执行

    2. 走到useState的时候,react内部其实走了updateState,拿到最新的状态:1,此时一切正常

    3. 走到handerClick,此时handerClick被重新创建,即handerClick指向了新的内存空间,值得注意的是:for循环接着往下走的时候,num所在的上下文并不是当前函数(新创建的函数),而是第一次初始化时创建的函数,而那个函数的上下文中,num永远都是0,所以console.log输出都是0

    相反:class写法,state发生变化handerClick没有被重新创建而已,并且this指向也没发生改变

  • 相关阅读:
    如何使用HTML和CSS创建动画条形图?
    ElasticSearch7.3学习(八)----倒排索引揭秘及初识分词器(Analyzer)
    mybatis oracle MERGE 利用oracle原理实现saveOrUpdate
    学习笔记11--其他相关安全标准与技术
    BOM对象介绍
    策略模式——设计模式
    LeetCode--180 连续出现的数字
    Java版工程项目管理系统平台+企业工程系统源码+助力工程企业实现数字化管理
    聊聊Mybatis的Executor之CachingExecutor
    各种语言如何连接到 OceanBase
  • 原文地址:https://blog.csdn.net/Laollaoaolao/article/details/126243421