React学习笔记——函数Function组件和类Class组件的setState的区别

本文探讨了React中函数组件和类组件的异同,包括它们对props和state的处理、生命周期方法以及性能差异。通过案例分析,展示了类组件在setTimeout中setState导致的异步更新问题,以及函数组件如何利用useState Hook处理状态。最后,文章提到了函数组件中useState Hook的两种更新方式的不同效果,强调了Hook在管理状态和副作用处理中的重要性。

关于React中函数Function组件和类Class组件的相同点和区别点,我想大家都已经知晓了,比如:

1、相同点

  • 无论是使用函数或是类来声明一个组件,它决不能修改它自己的 props
  • 所有 React 组件都必须是纯函数,并禁止修改其自身 props
  • React是单项数据流,父组件改变了属性,那么子组件视图会更新。、
  • 父组件props有变化时,子组件随之而改变
  • 属性 props 是外界传递过来的,状态 state 是组件本身的,状态可以在组件中任意修改
  • 组件的属性和状态改变都会更新视图。

2、不同点

区别函数组件类组件
生命周期没有
this没有
state没有
改变stateHook:useStatethis.setState()
性能高(不用实例化)低(需要实例化)

3、案例

(1)类class组件

不过,今天同事问了我一个简单的代码问题,之前也没认真想过,一下子没回答出来。
话不多说,看一下:

import React, { Component } from 'react'
class App extends Component {
    state={
        number:0
    }
    handleClick=()=>{
       for(let i = 0 ;i<5;i++){
           setTimeout(()=>{
               this.setState({ number:this.state.number+1 })
               console.log(this.state.number)
           },1000)
       }
    }
    render(){
        return(
            <div>
                当前的number:{this.state.number}
                <button onClick={this.handleClick}>点击我</button>
            </div>
        )
    }
}
export default App

在这里插入图片描述

(2)函数组件
import React ,{ useState } from 'react';
const App = () => {
    const [ num ,setNumber ] = useState(0)
    const handleClick1 = ()=> {
        for(let i=0; i<5;i++ ){
           setTimeout(() => {
                setNumber(num+1)
                console.log(num)
           }, 1000)
        }
    }
    return (
        <div>
            当前的num值:{num}
            <br/>
            <button onClick={handleClick1}>改变num</button>
        </div>
    );
};
export default App;

在这里插入图片描述

(3)对比结果

可以看出:
第一个类class组件,打印结果是:1 2 3 4 5,页面上显示的是5;
第二个函数Function组件,打印结果是:0 0 0 0 0,页面上显示的是1

这个结果看上去很唬人,认真分析一下:

  • 类class组件中,通过一个实例化的class,去维护组件中的各种状态。点击按钮,循环五次setTimeout,同时由于setState没有在react正常的函数里执行上下文,而是位于异步的setTimeout里面,所以批量更新的条件被破坏,可以同步拿到每次setState之后的值
    关于React批量更新可查看React学习笔记——this.setState的基础使用和不同传参方法详解
  • 函数Function组件中,没有一个状态去保存这些信息,它只是一个函数,每一次函数上下文执行,所有变量,常量都重新声明,执行完毕,再被垃圾机制回收。所以如上,无论setTimeout执行多少次,都是在当前函数上下文执行,此时num = 0不会变,之后setNumber执行,函数组件重新执行之后,num才变化。

结论:

  • 所以, 对于class组件,我们只需要实例化一次,实例中保存了组件的state等状态。对于每一次更新只需要调用render方法就可以。
  • 但是在function组件中,我们每一次更新都是一次新的函数执行,为了保存一些状态,执行一些副作用钩子,react-hooks应运而生,去帮助记录组件的状态,处理一些额外的副作用。

4、有趣拓展

对于函数Function的写法,在set的时候有函数型和对象型两种写法,我们观察一下这两种的区别:

import React ,{ useState } from 'react';
const App = () => {
    const [ num ,setNumber ] = useState(0)
    const [ val ,setVal ] = useState(0)
    const handleClick1 = ()=> {
        for(let i=0; i<5;i++ ){
           setTimeout(() => {
                setNumber(num+1)
                console.log('num',num)
                
           }, 1000)
        }
    }
    const handleClick2 = () =>{
        for(let i=0; i<5;i++ ){
            setTimeout(() => {
                 setVal(val=>val+1)
                 console.log('val',val)
            }, 1000)
        }
    }
    return (
        <div>
            当前的num值:{num}
            <br/>
            <button onClick={handleClick1}>改变num</button>
            <br/>
            当前的val值:{val}
            <br/>
            <button onClick={handleClick2}>改变val</button>
        </div>
    );
};
export default App;

在这里插入图片描述
可以看出,当里面是函数式的写法时,虽然每次打印的val值是0,但是他会依赖于上一次的状态,所以val值每次都会+1;而对象式的写法却不会。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值