当前位置: 首页 > news >正文

React中 类组件 与 函数组件 的区别

类组件 与 函数组件 的区别

  • 1. 类组件
  • 2. 函数组件
    • Hook
      • useState
      • useEffect
      • useCallback
      • useMemo
      • useContext
      • useRef
  • 3. 函数组件与类组件的区别
    • 3.1 表面差异
    • 3.2 最大不同
      • 原因

1. 类组件

在React中,类组件就是基于ES6语法,通过继承 React.component 得到的组件。

class Demo extends React.Component {// 初始化类组件的 statestate = {text: "111"};// 编写生命周期方法 didMountcomponentDidMount() {// 省略业务逻辑}// 编写自定义的实例方法changeText = (newText) => {// 更新 statethis.setState({text: newText});};// 编写生命周期方法 renderrender() {return (<div className="demoClass"><p>{this.state.text}</p><button onClick={() => this.changeText(222)}>点我修改</button></div>);}
}

2. 函数组件

在函数组件也称为无状态组件,顾名思义就是以函数形态存在的 React 组件。

hooks出现之前,react 中的函数组件通常只考虑负责UI的渲染,没有自身的状态,没有业务逻辑代码,是一个纯函数

下面这个函数组件就是一个纯函数,它的输出只由参数props决定,不受其他任何因素影响。

function DemoFunction(props) {const { text } = propsreturn (<div className="demoFunction"><p>{`function 组件所接收到的来自外界的文本内容是:[${text}]`}</p></div>);
}

但是这种函数组件一旦我们需要给组件加状态,那就只能将组件重写为类组件,因为函数组件没有实例,没有生命周期
所以我们说在 hook 之前的 函数组件和类组件最大的区别就是 状态的有无。

Hook

React Hooks 是从 React 16.8 版本推出的新特性,目的是解决 React 的状态共享以及组件生命周期管理混乱的问题。 React Hooks 的出现标志着,React 不会再存在无状态组件的情况,React 将只有类组件和函数组件的概念。

hooks为函数组件提供了状态,也支持在函数组件中进行数据获取、订阅事件解绑事件等等。

下面先介绍几个最基本的hook作为基础知识。

useState

const [count,setCount] = useState(0);

通过 useState 为组件提供状态。useState 的参数是 state 的初始值,他只有在组件第一次渲染的时候会生效,他的返回值是一个数组,第一个是 state,第二个是设置state的函数。

useEffect

//1. 不设置依赖项数组,那么在组件挂载时和每次渲染时,都会执行一次副作用
useEffect(() => {console.log("useEffect副作用执行");//用setTimeout模拟ajax请求setTimeout(() => {setList(result);}, 3000);});
//2. 设置依赖项为空数组,那么只有在组件挂载时执行副作用
useEffect(() => {console.log("useEffect副作用执行");setTimeout(() => {setList(result);}, 3000);},[]);
//3. 如果设置依赖项且不为空,那么在组件挂载时和数组中的依赖项发生变化时,副作用就会重新执行。useEffect(() => {console.log("useEffect副作用执行");setTimeout(() => {setList(result);}, 3000);}, [list]);

useEffect用于处理组件的副作用

  • 第一个参数是一个回调函数,在里面进行业务逻辑代码的书写(副作用操作)
    • 通常在副作用中进行ajax请求,事件的绑定与解绑,设置定时器与清除等等。
  • 第二个参数是依赖项数组,指定副作用函数的触发条件。
    • 如果不设置第二个参数,那么当该组件挂载和组件每渲染一次,副作用就会执行一次
    • 如果数组中的依赖设置为,那么只有在组件挂载时,该副作用才会执行
    • 如果数组中存在依赖项,当组件挂载时和依赖项数组中的依赖发生变化,那么该副作用就会重新执行

useCallback

用于缓存函数,以避免无效的函数重新创建。 第一个参数为要缓存的函数,第二个参数为依赖项数组,如果依赖发生了变化,那么就会生成一个新的函数;否则当组件重新渲染时,不会重新定义这个函数,而是会取缓存。

useMemo

用于缓存计算结果,以避免无效的计算重复执行。 第一个参数为要缓存的函数(注意实际被缓存的是函数被执行过后的值),第二个参数为依赖项数组,如果依赖发生了变化,那么就会重新执行这个函数,得到新的返回值;否则当组件重新渲染时,不会重新执行这个函数,而是直接取被缓存的该函数的返回值。

useCallbackuseMemo 都是在函数式组件中用作优化性能的。

默认情况下,当一个组件重新渲染时, React 将递归渲染它的所有子组件。组件中的函数就会重新被创建。因为在 JavaScript 中,function () {} 或者 () => {} 总是会生成不同的函数。

  • useCallback
    • 避免在内部编写额外的嵌套函数
    • 避免组件的重新渲染

比如说在父组件中接收的props有{ A,B,C },函数handleSubmit()依赖于A和B,将这个函数作为子组件的props),如果C发生变化,会导致重新创建一个函数handleSumit(),也就导致子组件的props是不同,从而引起子组件重新渲染,但其实这是不必要,这时就可以采用useCallback,将函数handleSubmit传递给useCallback,并设置依赖项([A,B]),保证只有依赖项(A,B)发生变化时,才会重新生成handleSubmit函数,子组件才会重新渲染,从而避免了组件内部重新创建函数,避免引起不必要的渲染。

  • useMemo
    • 避免无效的重新计算
    • 跳过组件的重新渲染

同理,比如说父组件中接收的props有{A,B,C},有一个对象count是依赖于A和B计算得出的,并将这个对象count作为子组件的props,正常情况当C发生变化,会导致重新创建对象count,导致传递给子组件的props不同,从而引起子组件的重新渲染,但这是不必要的重复渲染,这时就可以采用useMemo,将定义对象count的计算函数用useMemo包裹,并设置依赖项[A,B],这样就可以保证只有在依赖项发生变化时,才会重新执行计算函数生成新的count对象,子组件才会重新渲染,从而避免了组件内部重新进行无效计算,避免引起不必要的渲染。

useContext

用于跨组件通信,以便共享数据和功能。它接收一个上下文对象(通过 React.createContext 创建)并返回当前上下文的值。这样,函数组件就可以消费上下文中的数据,而不必通过一层层的属性传递。

import { createContext, useContext } from 'react';
const ThemeContext = createContext(null);export default function MyApp() {return (<ThemeContext.Provider value="dark"><Form /></ThemeContext.Provider>)
}function Form() {return (<Panel title="Welcome"><Button>Sign up</Button><Button>Log in</Button></Panel>);
}function Panel({ title, children }) {const theme = useContext(ThemeContext);const className = 'panel-' + theme;return (<section className={className}><h1>{title}</h1>{children}</section>)
}function Button({ children }) {const theme = useContext(ThemeContext);const className = 'button-' + theme;return (<button className={className}>{children}</button>);
}

useContext() 总是在调用它的组件 上面 寻找最近的 provider。它向上搜索, 不考虑 调用 useContext() 的组件中的 provider。

useRef

const ref = useRef(initialValue)
  • 用于在函数组件之间保存可变的引用,类似于类组件中的 ref。改变 ref 不会触发重新渲染。

  • 使用 ref 操作 DOM

    import { useRef } from 'react';
    export default function Form() {const inputRef = useRef(null);function handleClick() {inputRef.current.focus();}return (<><input ref={inputRef} /><MyInput ref={inputRef} />;// 无法获取自定义组件的 ref <button onClick={handleClick}>聚焦输入框</button></>);
    }
    
  • 无法获取自定义组件的 ref
    默认情况下,自定义组件不会暴露它们内部 DOM 节点的 ref。
    像这样将自定义子组件包装在 forwardRef 里,父级组件就可以得到它的 ref。

    import { forwardRef } from 'react';
    const MyInput = forwardRef(({ value, onChange }, ref) => 		{return (<inputvalue={value}onChange={onChange}ref={ref}/>);
    });
    export default MyInput;
    

3. 函数组件与类组件的区别

3.1 表面差异

  • 类组件有生命周期,函数组件没有
  • 类组件需要继承 Class,函数组件不需要
  • 类组件可以获取实例化的 this,并且基于 this 做各种操作,函数组件不行
  • 类组件内部可以定义并维护 state, 函数组件为无状态组件(可以通过hooks实现)

函数组件相比较类组件,优点是更轻量与灵活,便于逻辑的拆分复用。

3.2 最大不同

函数式组件捕获了渲染时所使用的值 , 这是两类组件最大的不同。

import React from "react";
import ReactDOM from "react-dom";import ProfilePageFunction from './ProfilePageFunction';
import ProfilePageClass from './ProfilePageClass';class App extends React.Component {state = {user: 'Dan',};render() {return (<><label><b>Choose profile to view: </b><selectvalue={this.state.user}onChange={e => this.setState({ user: e.target.value })}><option value="Dan">Dan</option><option value="Sophie">Sophie</option><option value="Sunil">Sunil</option></select></label><h1>Welcome to {this.state.user}’s profile!</h1><p>//函数组件<ProfilePageFunction user={this.state.user} /><b> (function)</b></p><p>//类组件<ProfilePageClass user={this.state.user} /><b> (class)</b></p><p>Can you spot the difference in the behavior?</p></>)}
}const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

类组件 —— ProfilePageClass.js

import React from 'react';class ProfilePage extends React.Component {showMessage = () => {alert('Followed ' + this.props.user);};handleClick = () => {setTimeout(this.showMessage, 3000);};render() {return <button onClick={this.handleClick}>Follow</button>;}
}
export default ProfilePage;

函数组件 —— ProfilePageFunction.js

import React from 'react';function ProfilePage(props) {const showMessage = () => {alert('Followed ' + props.user);};const handleClick = () => {setTimeout(showMessage, 3000);};return (<button onClick={handleClick}>Follow</button>);
}
export default ProfilePage;

仔细对比,以上代码的不同
在这里插入图片描述
函数组件的测试情况下,下拉框中选中 Dan,点击关注按钮,迅速将下拉框切换到Sophie,3秒之后,alert弹窗内容仍然是 Followed Dan

类组件的测试情况下,重复相同的动作,3秒之后,alert弹窗将会显示 Followed Sophie

此案例中,当父组件的state改变时,子组件进行重新渲染,子组件的props改变;

原因

  • 类组件:
    props改变(Dan->Sophie),类组件也改变了值,永远保持一致。

    原因:类组件捕获最新的值(永远保持一致)当实例的props属性发生修改时,class组件直接使用this(组件的实例),所以可以直接获取组件最新的props

  • 函数组件: 函数式组件捕获了渲染时所用的值
    当改变props时(Dan->Sophie),你会发现函数组件会渲染之前的值Dan这个名字。

    原因:函数式组件捕获了渲染所使用的值。在函数组件中,之前的props参数,已经因为javaScript闭包的特性,保存在内存之中,无法从外部进行修改(维护多个人的状态)。 所以在定时器执行callback时,打印的还是旧值。

下面是在javaScript闭包中的测试

<body><button onclick="openClick()">开始</button>  <button onclick="handleClick()">改变a的值</button>    
</body>
<script>
function parent(arg){let a=arg;return function children(){alert('a的值是:'+ a);}
}function openClick(){setTimeout(()=>{parent(111)();},3000);
}function handleClick(){parent(222);
}
</script>

当点击【开始】按钮时,会使用定时器在三秒后调用闭包函数,页面弹出a的值111,如果在这三秒内点击了【改变a的值】按钮,触发事件修改闭包的外层函数的作用域下的a的值,但到3秒时页面弹出a的值仍然是111。

相关文章:

React中 类组件 与 函数组件 的区别

类组件 与 函数组件 的区别 1. 类组件2. 函数组件HookuseStateuseEffectuseCallbackuseMemouseContextuseRef 3. 函数组件与类组件的区别3.1 表面差异3.2 最大不同原因 1. 类组件 在React中&#xff0c;类组件就是基于ES6语法&#xff0c;通过继承 React.component 得到的组件…...

GPT实战系列-智谱GLM-4的模型调用

GPT实战系列-智谱GLM-4的模型调用 GPT专栏文章&#xff1a; GPT实战系列-实战Qwen通义千问在Cuda 1224G部署方案_通义千问 ptuning-CSDN博客 GPT实战系列-ChatGLM3本地部署CUDA111080Ti显卡24G实战方案 GPT实战系列-Baichuan2本地化部署实战方案 GPT实战系列-让CodeGeeX2帮…...

AndroidStudio开发 相关依赖

1、com.google.zxing 用于二维码扫描 2、butterknife 用于简化findView 和 onClick操作 3、pub.devrel:easypermissions 简化权限请求的库 4、 网络请求框架(一)&#xff1a;android-async-http 网络请求框架(二)&#xff1a;xUtils 网络请求框架(三)&#xff1a;Volley Volley…...

Zookeeper详解(zk)

文章目录 Zookeeper 概念ZooKeeper的应用场景使用场景zk的原理ZooKeeper、Nacos、Eureka 和 Consul区别Zookeeper的数据结构zk集群脑裂如何解决ZAB 协议假如注册中心挂了&#xff0c;消费者还能调⽤服务吗&#xff0c;用什么调用的dubbo注册中心为什么选择 Zookeeper关于zookee…...

BSD-3-Clause是一种开源软件许可协议

BSD-3-Clause是一种开源软件许可协议&#xff0c;也称为BSD三条款许可证。它是BSD许可证家族中的一种&#xff0c;是一种宽松的许可证&#xff0c;允许软件自由使用、修改和重新分发&#xff0c;同时也保留了一些版权和责任方面的规定。 BSD-3-Clause许可证的主要特点包括以下…...

持续集成平台 02 jenkins plugin 插件

拓展阅读 Devops-01-devops 是什么&#xff1f; Devops-02-Jpom 简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件 代码质量管理 SonarQube-01-入门介绍 项目管理平台-01-jira 入门介绍 缺陷跟踪管理系统&#xff0c;为针对缺陷管理、任务追踪和项目管理的商业…...

LoadBalancerCacheManager not available, returning delegate without caching

警告&#xff1a;LoadBalancerCacheManager not available, returning delegate without caching 背景&#xff1a;更换了redis集群 解决方案&#xff1a; 重启gateway网关服务 也就是重启引用下面这个包的服务 <dependency><groupId>org.springframework.cloud…...

机器学习金融应用技术指南

1 范围 本文件提供了金融业开展机器学习应用涉及的体系框架、计算资源、数据资源、机器学习引擎、机 器学习服务、安全管理、内控管理等方面的建议。 本文件适用于开展机器学习金融应用的金融机构、技术服务商、第三方安全评估机构等。 2 规范性引用文件 下列文件中的内容通过…...

ES6生成器(Generator)

一、function* 概念简介&#xff1a;function* - JavaScript | MDN (mozilla.org) function* 声明创建一个绑定到给定名称的新生成器函数。生成器函数可以退出&#xff0c;并在稍后重新进入&#xff0c;其上下文&#xff08;变量绑定&#xff09;会在重新进入时保存。 1.1 y…...

大模型主流微调训练方法总结 LoRA、Adapter、Prefix-tuning、P-tuning、Prompt-tuning 并训练自己的数据集

大模型主流微调训练方法总结 LoRA、Adapter、Prefix-tuning、P-tuning、Prompt-tuning 概述 大模型微调(finetuning)以适应特定任务是一个复杂且计算密集型的过程。本文训练测试主要是基于主流的的微调方法:LoRA、Adapter、Prefix-tuning、P-tuning和Prompt-tuning,并对…...

【No.13】蓝桥杯二分查找|整数二分|实数二分|跳石头|M次方根|分巧克力(C++)

二分查找算法 知识点 二分查找原理讲解在单调递增序列 a 中查找 x 或 x 的后继在单调递增序列 a 中查找 x 或 x 的前驱 二分查找算法讲解 枚举查找即顺序查找&#xff0c; 实现原理是逐个比较数组 a[0:n-1] 中的元素&#xff0c;直到找到元素 x 或搜索整个数组后确定 x 不在…...

【蓝桥杯-单片机】基于定时器的倒计时程序设计

基于定时器的倒计时程序 题目如下所示&#xff1a; 实现过程中遇到的一些问题 01 如何改变Seg_Buf数组的值数码管总是一致地显示0 1 2 3 4 5 首先这个问题不是在main.c中关于数码管显示部分的逻辑错误&#xff0c;就是发生在数码管的底层错误。 检查了逻辑部分&#xff…...

QT:三大特性

QT的三大特性&#xff1a; 1、信号与槽 2、内存管理 3、事件处理 1、信号与槽 当信号产生时&#xff0c;就会自动调用绑定的槽函数。 自定义信号: 类中需要添加O_OBJECT宏 声明: signals标签之下进行声明 定义&#xff1a; 信号不需要定义 …...

无服务器推理在大语言模型中的未来

服务器无服务器推理的未来&#xff1a;大型语言模型 摘要 随着大型语言模型(LLM)如GPT-4和PaLM的进步&#xff0c;自然语言任务的能力得到了显著提升。LLM被广泛应用于聊天机器人、搜索引擎和编程助手等场景。然而&#xff0c;由于LLM对GPU和内存的巨大需求&#xff0c;其在规…...

【linux】CentOS查看系统信息

一、查看版本号 在CentOS中&#xff0c;可以通过多种方法来查看版本号。以下是几种常用的方法&#xff1a; 使用cat命令查看/etc/centos-release文件&#xff1a; CentOS的版本信息存储在/etc/centos-release文件中。可以使用cat命令来显示该文件的内容&#xff0c;从而获得C…...

部署dagu_1.12.10+replicadb0.15.1+sqlline1.12

下载所需的文件并上传到服务器 dagu_1.12.10(选择适合自己的版本): https://gh.api.99988866.xyz/https://github.com/dagu-dev/dagu/releases/download/v1.12.10/dagu_1.12.10_linux_amd64.tar.gzreplicadb0.15.1(包含了sqlline1.12): https://download.csdn.net/download/u0…...

基于Java中的SSM框架实现社会保险管理系统项目【项目源码+论文说明】

摘要 改革开放的浪潮已近深深的键入人心&#xff0c;随之而带来了我国社会主义市场经济体制的不断完善和建立健全&#xff0c;作为国家基本保障之一的社会保险系统&#xff0c;我们不单单要把握社保金额的进展和状态&#xff0c;还需要对社会保障基金开展全面、科学、可持续的…...

24计算机考研调剂 | 江西理工大学

能源、化工、计算机&#xff08;0854&#xff09;等相关方向有3个调剂名额 考研调剂招生信息 学校:江西理工大学 专业:工学->治金工程 年级:2024 招生人数:3 招生状态:正在招生中 联系方式:********* (为保护个人隐私,联系方式仅限APP查看) 补充内容 能源、化工、计…...

Sentry(Android)源码解析

本文字数&#xff1a;16030字 预计阅读时间&#xff1a;40分钟 01 前言 Sentry是一个日志记录、错误上报、性能监控的开源框架&#xff0c;支持众多平台&#xff1a; 其使用方式在本文不进行说明了&#xff0c;大家可参照官方文档&#xff1a;https://docs.sentry.io/platforms…...

Android StateLayout状态页

文章目录 Android StateLayout状态页概述源码使用源码下载 Android StateLayout状态页 概述 StateLayout&#xff08;状态页&#xff09;包含&#xff1a;加载中页面&#xff0c;错误页面&#xff0c;空页面&#xff0c;内含状态默认页面&#xff0c;支持自定义页面。 源码 …...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

蓝桥杯 冶炼金属

原题目链接 &#x1f527; 冶炼金属转换率推测题解 &#x1f4dc; 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V&#xff0c;是一个正整数&#xff0c;表示每 V V V 个普通金属 O O O 可以冶炼出 …...

嵌入式常见 CPU 架构

架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集&#xff0c;单周期执行&#xff1b;低功耗、CIP 独立外设&#xff1b;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel&#xff08;原始…...