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
用于缓存计算结果,以避免无效的计算重复执行。 第一个参数为要缓存的函数(注意实际被缓存的是函数被执行过后的值),第二个参数为依赖项数组,如果依赖发生了变化,那么就会重新执行这个函数,得到新的返回值;否则当组件重新渲染时,不会重新执行这个函数,而是直接取被缓存的该函数的返回值。
useCallback
,useMemo
都是在函数式组件中用作优化性能的。默认情况下,当一个组件重新渲染时, 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中,类组件就是基于ES6语法,通过继承 React.component 得到的组件…...

GPT实战系列-智谱GLM-4的模型调用
GPT实战系列-智谱GLM-4的模型调用 GPT专栏文章: 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、 网络请求框架(一):android-async-http 网络请求框架(二):xUtils 网络请求框架(三):Volley Volley…...
Zookeeper详解(zk)
文章目录 Zookeeper 概念ZooKeeper的应用场景使用场景zk的原理ZooKeeper、Nacos、Eureka 和 Consul区别Zookeeper的数据结构zk集群脑裂如何解决ZAB 协议假如注册中心挂了,消费者还能调⽤服务吗,用什么调用的dubbo注册中心为什么选择 Zookeeper关于zookee…...
BSD-3-Clause是一种开源软件许可协议
BSD-3-Clause是一种开源软件许可协议,也称为BSD三条款许可证。它是BSD许可证家族中的一种,是一种宽松的许可证,允许软件自由使用、修改和重新分发,同时也保留了一些版权和责任方面的规定。 BSD-3-Clause许可证的主要特点包括以下…...
持续集成平台 02 jenkins plugin 插件
拓展阅读 Devops-01-devops 是什么? Devops-02-Jpom 简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件 代码质量管理 SonarQube-01-入门介绍 项目管理平台-01-jira 入门介绍 缺陷跟踪管理系统,为针对缺陷管理、任务追踪和项目管理的商业…...
LoadBalancerCacheManager not available, returning delegate without caching
警告:LoadBalancerCacheManager not available, returning delegate without caching 背景:更换了redis集群 解决方案: 重启gateway网关服务 也就是重启引用下面这个包的服务 <dependency><groupId>org.springframework.cloud…...

机器学习金融应用技术指南
1 范围 本文件提供了金融业开展机器学习应用涉及的体系框架、计算资源、数据资源、机器学习引擎、机 器学习服务、安全管理、内控管理等方面的建议。 本文件适用于开展机器学习金融应用的金融机构、技术服务商、第三方安全评估机构等。 2 规范性引用文件 下列文件中的内容通过…...
ES6生成器(Generator)
一、function* 概念简介:function* - JavaScript | MDN (mozilla.org) function* 声明创建一个绑定到给定名称的新生成器函数。生成器函数可以退出,并在稍后重新进入,其上下文(变量绑定)会在重新进入时保存。 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 的前驱 二分查找算法讲解 枚举查找即顺序查找, 实现原理是逐个比较数组 a[0:n-1] 中的元素,直到找到元素 x 或搜索整个数组后确定 x 不在…...

【蓝桥杯-单片机】基于定时器的倒计时程序设计
基于定时器的倒计时程序 题目如下所示: 实现过程中遇到的一些问题 01 如何改变Seg_Buf数组的值数码管总是一致地显示0 1 2 3 4 5 首先这个问题不是在main.c中关于数码管显示部分的逻辑错误,就是发生在数码管的底层错误。 检查了逻辑部分ÿ…...

QT:三大特性
QT的三大特性: 1、信号与槽 2、内存管理 3、事件处理 1、信号与槽 当信号产生时,就会自动调用绑定的槽函数。 自定义信号: 类中需要添加O_OBJECT宏 声明: signals标签之下进行声明 定义: 信号不需要定义 …...
无服务器推理在大语言模型中的未来
服务器无服务器推理的未来:大型语言模型 摘要 随着大型语言模型(LLM)如GPT-4和PaLM的进步,自然语言任务的能力得到了显著提升。LLM被广泛应用于聊天机器人、搜索引擎和编程助手等场景。然而,由于LLM对GPU和内存的巨大需求,其在规…...

【linux】CentOS查看系统信息
一、查看版本号 在CentOS中,可以通过多种方法来查看版本号。以下是几种常用的方法: 使用cat命令查看/etc/centos-release文件: CentOS的版本信息存储在/etc/centos-release文件中。可以使用cat命令来显示该文件的内容,从而获得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框架实现社会保险管理系统项目【项目源码+论文说明】
摘要 改革开放的浪潮已近深深的键入人心,随之而带来了我国社会主义市场经济体制的不断完善和建立健全,作为国家基本保障之一的社会保险系统,我们不单单要把握社保金额的进展和状态,还需要对社会保障基金开展全面、科学、可持续的…...
24计算机考研调剂 | 江西理工大学
能源、化工、计算机(0854)等相关方向有3个调剂名额 考研调剂招生信息 学校:江西理工大学 专业:工学->治金工程 年级:2024 招生人数:3 招生状态:正在招生中 联系方式:********* (为保护个人隐私,联系方式仅限APP查看) 补充内容 能源、化工、计…...

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

Android StateLayout状态页
文章目录 Android StateLayout状态页概述源码使用源码下载 Android StateLayout状态页 概述 StateLayout(状态页)包含:加载中页面,错误页面,空页面,内含状态默认页面,支持自定义页面。 源码 …...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...

Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...