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

React底层常见的设计模式

在React中,常见的设计模式为开发者提供了结构化和可重用的解决方案,有助于提高代码的可维护性和可扩展性。以下是对React中几种常见设计模式的详细解析,并附上示例代码和注释:

1. 容器组件与展示组件模式(Container/Presentational Pattern)

描述
容器组件负责数据获取、状态管理和业务逻辑,而展示组件仅负责渲染UI,不直接管理状态。

示例代码

// 展示组件:TodoItem.js
import React from 'react';const TodoItem = ({ todo }) => (<div><span>{todo.text}</span><button onClick={() => alert(`Completed ${todo.text}`)}>Complete</button></div>
);export default TodoItem;// 容器组件:TodoList.js
import React, { Component } from 'react';
import TodoItem from './TodoItem';class TodoList extends Component {state = {todos: [{ id: 1, text: 'Learn React' },{ id: 2, text: 'Learn Redux' },],};render() {return (<div><h1>Todo List</h1><ul>{this.state.todos.map(todo => (<li key={todo.id}><TodoItem todo={todo} /></li>))}</ul></div>);}
}export default TodoList;

注释

  • TodoItem是一个展示组件,它接收一个todo对象作为props,并渲染出对应的文本和按钮。
  • TodoList是一个容器组件,它管理一个todos状态数组,并在渲染时遍历该数组,为每个todo项渲染一个TodoItem组件。

2. 高阶组件模式(Higher-Order Component Pattern, HOC)

描述
高阶组件是一个函数,它接收一个组件作为参数,并返回一个新的组件。这个新组件可以访问原始组件的props,并可以添加额外的props或行为。

示例代码

// 高阶组件:withLogging.js
import React from 'react';const withLogging = (WrappedComponent) => {return class extends React.Component {componentDidMount() {console.log(`${WrappedComponent.name} mounted`);}componentWillUnmount() {console.log(`${WrappedComponent.name} will unmount`);}render() {return <WrappedComponent {...this.props} />;}};
};// 使用高阶组件的组件:EnhancedTodoItem.js
import React from 'react';
import withLogging from './withLogging';
import TodoItem from './TodoItem'; // 假设TodoItem是上面定义的展示组件// 注意:这里我们实际上是在增强TodoItem组件,但为了示例清晰,我们假设有一个新的组件EnhancedTodoItem
const EnhancedTodoItem = withLogging(TodoItem);// 通常情况下,你会直接使用EnhancedTodoItem而不是TodoItem
// 但在这个例子中,我们只是为了展示HOC的用法,所以EnhancedTodoItem和TodoItem功能相同,只是多了日志记录。// 实际上,你可能会在EnhancedTodoItem中添加更多的逻辑或props。
export default EnhancedTodoItem;

注意:在上面的withLogging示例中,我们实际上没有直接对TodoItem进行增强(因为TodoItem已经是一个纯函数组件,并且没有额外的逻辑需要添加),但为了展示HOC的用法,我们假设有一个新的组件EnhancedTodoItem使用了这个HOC。在实际应用中,你会在HOC中添加额外的逻辑或props,并将其应用于需要增强的组件。

另外,由于TodoItem是一个函数组件,它没有name属性,所以console.log中的${WrappedComponent.name}可能不会显示你期望的名字。在实际应用中,你可能需要为函数组件添加一个displayName静态属性或使用其他方法来标识组件。

修正后的示例(为函数组件添加displayName):

// TodoItem.js(添加displayName)
import React from 'react';const TodoItem = ({ todo }) => (// ...之前的代码
);TodoItem.displayName = 'TodoItem'; // 添加displayName以便在日志中正确显示组件名export default TodoItem;

这样,当使用withLogging高阶组件时,日志中就会正确地显示TodoItem mountedTodoItem will unmount

当然,除了之前提到的容器组件与展示组件模式和高阶组件模式外,React中还有其他常见的设计模式。以下是对这些模式的详细解析,并附上示例代码和注释:

3. 渲染属性模式(Render Props Pattern)

描述
渲染属性模式是一种将函数作为属性传递给组件的技术,该函数返回一个React元素。这种模式允许组件之间共享代码和逻辑。

示例代码

// MouseTracker.js
import React, { useState } from 'react';const MouseTracker = ({ render }) => {const [position, setPosition] = useState({ x: 0, y: 0 });const handleMouseMove = (event) => {setPosition({ x: event.clientX, y: event.clientY });};return (<div style={{ height: '100vh' }} onMouseMove={handleMouseMove}>{render(position)}</div>);
};export default MouseTracker;// App.js
import React from 'react';
import MouseTracker from './MouseTracker';const App = () => (<MouseTrackerrender={({ x, y }) => (<h1>鼠标的当前位置是 ({x}, {y})</h1>)}/>
);export default App;

注释

  • MouseTracker组件接收一个render属性,该属性是一个函数,它接收鼠标位置作为参数,并返回一个React元素。
  • App组件中,我们使用MouseTracker组件,并传递一个函数作为render属性,该函数根据鼠标位置渲染一个h1元素。

4. 自定义钩子模式(Custom Hook Pattern)

描述
自定义钩子允许你将组件逻辑提取到可重用的函数中。它们可以让你在不增加组件类的情况下复用状态逻辑。

示例代码

// useFetch.js
import { useState, useEffect } from 'react';const useFetch = (url) => {const [data, setData] = useState(null);const [loading, setLoading] = useState(true);const [error, setError] = useState(null);useEffect(() => {fetch(url).then(response => {if (!response.ok) {throw new Error('Network response was not ok');}return response.json();}).then(jsonData => {setData(jsonData);setLoading(false);}).catch(error => {setError(error);setLoading(false);});}, [url]);return { data, loading, error };
};export default useFetch;// DataDisplay.js
import React from 'react';
import useFetch from './useFetch';const DataDisplay = ({ url }) => {const { data, loading, error } = useFetch(url);if (loading) return <p>Loading...</p>;if (error) return <p>Error: {error.message}</p>;return (<pre>{JSON.stringify(data, null, 2)}</pre>);
};export default DataDisplay;

注释

  • useFetch是一个自定义钩子,它接收一个URL作为参数,并返回一个包含数据、加载状态和错误信息的对象。
  • DataDisplay组件使用useFetch钩子来获取数据,并根据加载状态和错误信息渲染相应的UI。

5. 组合模式(Composite Pattern)

描述
组合模式允许你将对象组合成树形结构以表示“部分-整体”的层次结构。在React中,这通常体现在组件树的设计上。

示例代码(简化版):

// Accordion.js
import React, { useState } from 'react';const Accordion = ({ children }) => {const [activeIndex, setActiveIndex] = useState(null);const handleItemClick = (index) => {setActiveIndex(index);};return (<div>{React.Children.map(children, (child, index) =>React.cloneElement(child, {isActive: index === activeIndex,onItemClick: () => handleItemClick(index),}))}</div>);
};// AccordionItem.js
import React from 'react';const AccordionItem = ({ title, children, isActive, onItemClick }) => (<div><h2 onClick={onItemClick}>{title}</h2>{isActive && <div>{children}</div>}</div>
);export { Accordion, AccordionItem };// App.js
import React from 'react';
import { Accordion, AccordionItem } from './Accordion';const App = () => (<Accordion><AccordionItem title="Item 1">Content 1</AccordionItem><AccordionItem title="Item 2">Content 2</AccordionItem><AccordionItem title="Item 3">Content 3</AccordionItem></Accordion>
);export default App;

注释

  • Accordion组件接收子组件(AccordionItem组件)作为参数,并管理哪个项目处于活动状态。
  • AccordionItem组件接收标题、子组件、活动状态和点击事件处理器作为props,并根据活动状态渲染内容。
  • App组件中,我们使用Accordion组件,并传递多个AccordionItem组件作为其子组件。

这些设计模式在React开发中非常常见,它们有助于提高代码的可维护性、可扩展性和重用性。

相关文章:

React底层常见的设计模式

在React中&#xff0c;常见的设计模式为开发者提供了结构化和可重用的解决方案&#xff0c;有助于提高代码的可维护性和可扩展性。以下是对React中几种常见设计模式的详细解析&#xff0c;并附上示例代码和注释&#xff1a; 1. 容器组件与展示组件模式&#xff08;Container/P…...

从零基础到通过考试

1. 学习资源与实践平台 使用Proving Grounds进行靶机练习 OSCP的备考过程中&#xff0c;实战练习占据了非常重要的地位。Proving Grounds&#xff08;PG&#xff09;是一个由Offensive Security提供的练习平台&#xff0c;拥有152个靶机&#xff0c;涵盖了从基础到进阶的多种…...

UniApp 按钮组件 open-type 属性详解:功能、场景与平台差异

文章目录 引言一、open-type 基础概念1.1 核心作用1.2 通用使用模板 二、主流 open-type 值详解2.1 contact - 客服会话功能说明平台支持代码示例 2.2 share - 内容转发功能说明平台支持注意事项 2.3 getUserInfo - 获取用户信息功能说明平台支持代码示例 2.4 getPhoneNumber -…...

【无标题】ABP更换MySql数据库

原因&#xff1a;ABP默认使用的数据库是sqlServer&#xff0c;本地没有安装sqlServer&#xff0c;安装的是mysql&#xff0c;需要更换数据库 ABP版本&#xff1a;9.0 此处以官网TodoApp项目为例 打开EntityFrameworkCore程序集&#xff0c;可以看到默认使用的是sqlServer&…...

大模型微调入门(Transformers + Pytorch)

目标 输入&#xff1a;你是谁&#xff1f; 输出&#xff1a;我们预训练的名字。 训练 为了性能好下载小参数模型&#xff0c;普通机器都能运行。 下载模型 # 方式1&#xff1a;使用魔搭社区SDK 下载 # down_deepseek.py from modelscope import snapshot_download model_…...

【开源免费】基于SpringBoot+Vue.JS网络海鲜市场系统(JAVA毕业设计)

本文项目编号 T 222 &#xff0c;文末自助获取源码 \color{red}{T222&#xff0c;文末自助获取源码} T222&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...

在线会议时, 笔记本电脑的麦克风收音效果差是为什么

背景 最近在线面试. 使用腾讯会议或者飞书, 戴耳机参加在线面试, 遇到好几个面试官说我的音质不好. 一直没在意, 后来反思, 应该是电脑哪里出了问题. 排查 先买了一副品牌有线耳机, 测试后本地录制的声音仍然品质很差去掉耳机延长线后, 麦克风品质仍然很差最终找到答案, 原…...

理解文件系统

目录 文件系统 内存文件与磁盘文件的区别 初识inode 磁盘的概念 磁盘分区与格式化介绍 EXT2文件系统的存储方案 软硬链接 软连接 ​编辑 硬链接 软硬链接的区别 文件的三个时间 文件系统 内存文件与磁盘文件的区别 我们知道文件可以分为磁盘文件和内存文件&#…...

第二十四:5.2【搭建 pinia 环境】axios 异步调用数据

第一步安装&#xff1a;npm install pinia 第二步&#xff1a;操作src/main.ts 改变里面的值的信息&#xff1a; <div class"count"><h2>当前求和为&#xff1a;{{ sum }}</h2><select v-model.number"n">  // .number 这里是…...

Vue2+Element实现Excel文件上传下载预览【超详细图解】

目录 一、需求背景 二、落地实现 1.文件上传 图片示例 HTML代码 业务代码 2.文件下载 图片示例 方式一&#xff1a;代码 方式二&#xff1a;代码 3.文件预览 图片示例 方式一&#xff1a;代码 方式二&#xff1a;代码 一、需求背景 在一个愉快的年后&#xff…...

C# 装箱(Boxing)与拆箱(Unboxing)

C# 装箱&#xff08;Boxing&#xff09;与拆箱&#xff08;Unboxing&#xff09; 在 C# 中&#xff0c;装箱和拆箱是与值类型&#xff08;如结构体&#xff09;和引用类型&#xff08;如类&#xff09;之间的转换相关的操作。它们是类型系统的一部分&#xff0c;但如果不正确使…...

【AD】3-10 原理图PDF导出

文件—智能PDF 多页原理图导出 导出设置时选择工程&#xff0c;可自行选择导出一页或多页原理图&#xff0c;一般PCB不用导出...

SQL命令详解之增删改数据

目录 简介 1 添加数据 1.1 基础语法 1.2 SQL 练习 2 修改数据 2.1 基础语法 2.2 SQL 练习 ​3 删除数据 3.1 基础语法 3.2 SQL 练习 总结 简介 在数据库操作中&#xff0c;增、删、改是最基础的操作&#xff0c;它们通常对应着SQL中的INSERT、DELETE和UPDATE命令。…...

Docker 部署 MinIO 对象存储服务

Docker 部署 MinIO 对象存储服务 前言一、准备工作1. 安装 Docker2. 确认服务器架构 二、设置 MinIO 容器的目录结构三、启动一个临时的 MinIO 容器来获取配置文件四、复制 MinIO 配置文件到本地目录五、删除临时 MinIO 容器六、创建并运行 MinIO 容器&#xff0c;挂载本地目录…...

IP段转CIDR:原理Java实现

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…...

翻译: 深入分析LLMs like ChatGPT 一

大家好&#xff0c;我想做这个视频已经有一段时间了。这是一个全面但面向普通观众的介绍&#xff0c;介绍像ChatGPT这样的大型语言模型。我希望通过这个视频让大家对这种工具的工作原理有一些概念性的理解。 首先&#xff0c;我们来谈谈你在这个文本框里输入内容并点击回车后背…...

springboot之HTML与图片生成

背景 后台需要根据字段动态生成HTML&#xff0c;并生成图片&#xff0c;发送邮件到给定邮箱 依赖 <!-- freemarker模板引擎--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifa…...

数据结构(初阶)(三)----单链表

单链表 概念 概念&#xff1a;链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 结点 与顺序表不同的是&#xff0c;链表的结构类似于带车头的火车车厢&#xff0c;&#xff0c;链表的每个车厢都是独立…...

ChatGPT与DeepSeek:AI语言模型的巅峰对决

目录 引言 一、ChatGPT 与 DeepSeek 简介 &#xff08;一&#xff09;ChatGPT &#xff08;二&#xff09;DeepSeek 二、技术原理剖析 &#xff08;一&#xff09;ChatGPT 技术原理 &#xff08;二&#xff09;DeepSeek 技术原理 &#xff08;三&#xff09;技术原理对比…...

DaoCloud 亮相 2025 GDC丨开源赋能 AI 更多可能

2025 年 2 月 21 日至 23 日&#xff0c;上海徐汇西岸&#xff0c;2025 全球开发者先锋大会以 “模塑全球&#xff0c;无限可能” 的主题&#xff0c;围绕云计算、机器人、元宇宙等多元领域&#xff0c;探讨前沿技术创新、应用场景拓展和产业生态赋能&#xff0c;各类专业论坛、…...

从零实现 Llama 3:架构拆解与实现细节

本文参考以下英文教程撰写&#xff1a;https://pub.towardsai.net/build-your-own-llama-3-architecture-from-scratch-using-pytorch-2ce1ecaa901c 第一次看到有人把 Llama 3 从零实现一遍&#xff0c;我就知道这件事值得认真做一次。因为只有真正写出来&#xff0c;才能体会…...

解锁浏览器超能力:Greasy Fork用户脚本平台完全指南

解锁浏览器超能力&#xff1a;Greasy Fork用户脚本平台完全指南 【免费下载链接】greasyfork An online repository of user scripts. 项目地址: https://gitcode.com/gh_mirrors/gr/greasyfork 认知启蒙&#xff1a;重新认识浏览器脚本的价值 还在为浏览器功能不足烦恼…...

OpenClaw隐私方案:Kimi-VL-A3B-Thinking本地处理医疗影像数据分析

OpenClaw隐私方案&#xff1a;Kimi-VL-A3B-Thinking本地处理医疗影像数据分析 1. 为什么医疗数据必须留在本地&#xff1f; 去年参与一个医学研究项目时&#xff0c;团队需要分析3000多份CT影像。当我们尝试使用某云服务时&#xff0c;合规部门直接叫停——这些包含患者面部特…...

Webfunny前端监控系统安全防护终极指南:SQL注入防护与API鉴权最佳实践

Webfunny前端监控系统安全防护终极指南&#xff1a;SQL注入防护与API鉴权最佳实践 【免费下载链接】webfunny_monitor 【免费社区版】【企业版】Webfunny是一款集全链路监控和埋点系统于一体的大数据分析系统&#xff0c;我们致力于解决线上的疑难杂症和精细化分析业务数据&…...

从TCP BBR到网卡中断绑定:给K8s节点和游戏服务器做一次网络延迟‘大保健’

从TCP BBR到网卡中断绑定&#xff1a;给K8s节点和游戏服务器做一次网络延迟‘大保健’ 在云原生和高性能计算领域&#xff0c;网络延迟的毫秒级波动可能引发连锁反应——Kubernetes集群中某个Pod的响应延迟会导致整个微服务链路雪崩&#xff0c;而游戏服务器上50ms的卡顿足以让…...

SN75453与非门电路设计:如何正确选择上下拉电阻值(附计算公式)

SN75453与非门电路设计&#xff1a;如何正确选择上下拉电阻值&#xff08;附计算公式&#xff09; 在数字电路设计中&#xff0c;与非门是最基础的逻辑门之一&#xff0c;而SN75453作为一款经典的TTL与非门芯片&#xff0c;广泛应用于各种控制系统中。但很多工程师在实际应用时…...

新手必看:AI人脸隐私卫士从部署到使用,完整操作指南

新手必看&#xff1a;AI人脸隐私卫士从部署到使用&#xff0c;完整操作指南 1. 引言&#xff1a;为什么需要AI人脸隐私保护&#xff1f; 在日常生活中&#xff0c;我们经常需要分享照片到社交媒体或工作群聊。但你是否想过&#xff0c;这些照片中可能无意间暴露了他人的隐私信…...

OpenClaw飞书机器人配置:基于gemma-3-12b-it的对话自动化

OpenClaw飞书机器人配置&#xff1a;基于gemma-3-12b-it的对话自动化 1. 为什么选择OpenClaw飞书本地模型组合 去年我接手了一个需要频繁处理文档和数据的项目&#xff0c;每天要花3小时在飞书群聊和本地文件之间来回切换。尝试过各种自动化工具后&#xff0c;最终选择了Open…...

RVC与ElevenLabs对比:开源可控性vs商业易用性深度分析

RVC与ElevenLabs对比&#xff1a;开源可控性vs商业易用性深度分析 想用AI克隆自己的声音&#xff0c;或者让喜欢的角色开口唱歌&#xff1f;现在市面上有两大主流选择&#xff1a;开源的RVC和商业化的ElevenLabs。一个免费但需要折腾&#xff0c;一个付费但开箱即用。到底哪个…...

OpenClaw本地化优势:Qwen3-14b_int4_awq模型数据安全实践

OpenClaw本地化优势&#xff1a;Qwen3-14b_int4_awq模型数据安全实践 1. 为什么选择本地化部署 去年我在处理一批客户调研数据时&#xff0c;遇到了一个棘手问题——调研报告包含大量敏感信息&#xff0c;但团队需要AI辅助分析。当时尝试了几个云端方案&#xff0c;要么因为数…...