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

函数组件和class组件

函数组件

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

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

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

class组件

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

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

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

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

直接看代码

class组件

class Index extends React.Component<any,any>{
    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 <div>
            <button onClick={ this.handerClick } >num++</button>
        </div>
    }
}

函数组件

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 <button onClick={ handerClick } >{ num }</button>
}

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

第一个例子: 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

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

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指向也没发生改变

猜你喜欢

转载自blog.csdn.net/Laollaoaolao/article/details/126243421