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

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

全面解析数据库:从基础概念到前沿应用​

在数字化时代&#xff0c;数据已成为企业和社会发展的核心资产&#xff0c;而数据库作为存储、管理和处理数据的关键工具&#xff0c;在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理&#xff0c;到社交网络的用户数据存储&#xff0c;再到金融行业的交易记录处理&a…...