当前位置: 首页 > 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;各类专业论坛、…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...