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开发中非常常见,它们有助于提高代码的可维护性、可扩展性和重用性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/25878.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

类和对象——const修饰的类的对象和函数

const修饰的类的对象和函数 const成员函数和const对象1 const成员函数2 调用关系3 const在成员函数中的位置4 取地址&及const取地址操作符重载 const成员函数和const对象 1 const成员函数 将const修饰的“成员函数”称之为const成员函数&#xff0c;const修饰类成员函数&…

unity学习61:UI布局layout

目录 1 布局 layout 1.1 先准备测试UI,新增这样一组 panel 和 image 1.2 新增 vertical layout 1.3 现在移动任意一个image 都会影响其他 1.3.1 对比 如果没有这个&#xff0c;就会是覆盖效果了 1.3.2 对比 如果没有这个&#xff0c;就会是覆盖效果了 1.4 总结&#xf…

第48天:Web开发-JavaEE应用依赖项Log4j日志Shiro验证FastJson数据XStream格式

#知识点 1、安全开发-JavaEE-第三方依赖开发安全 2、安全开发-JavaEE-数据转换&FastJson&XStream 3、安全开发-JavaEE-Shiro身份验证&Log4j日志处理 一、Log4j 一个基于Java的日志记录工具&#xff0c;当前被广泛应用于业务系统开发&#xff0c;开发者可以利用该工…

使用tkinter有UI方式来拷贝Excel文件

有需求使用tkinter 有用户交互界面来拷贝Excel文件&#xff0c;最后进行打包完成 代码如下&#xff0c;实现思路是先使用tkinter库选择Excel路径&#xff0c;然后保存到txt文档&#xff0c; import time import tkinter from pathlib import Path from typing import Optiona…

【六祎 - Note】Redis缓存设计模型,备忘录;

Redis缓存备忘录 from to : 点击访问源地址

天佐.乾坤袋 基于抽屉式文件存储的NoSql数据库

天佐.乾坤袋 天佐.乾坤袋 简介 天佐.乾坤袋 基于抽屉式文件存储的NoSql数据库&#xff0c;可用于文件打包&#xff0c;数据整合&#xff0c;加密存放等多种用途。可以方便快捷的搭建和部署存储应用的系统。 传说: 弥勒所有&#xff0c;专做储物之用。拥有不可思议之力&#x…

【前端基础】Day 5 CSS浮动

目录 1. 浮动 1.1 标准流&#xff08;普通流/文档流&#xff09; 1.2 浮动 1.2.1 浮动的特性 1.2.2 浮动元素常和标准流父级搭配使用 1.2.3 案例 2. 常见网页布局 2.1 常见网页布局 2.2 浮动布局注意点 3. 清除浮动 3.1 原因 3.2 清除浮动的本质 3.3 清除浮动的方…

硬编码(三)经典变长指令一

我们在前两节的硬编码中学习了定长指令&#xff0c;接下来学习变长指令 对于定长指令&#xff0c;我们通过opcode便可知该指令的长度&#xff0c;但是对于变长指令却是不可知的。变长指令长度由opcode&#xff0c;ModR/M&#xff0c;SIB共同决定。变长指令通常在需要操作内存的…

【免费】YOLO[笑容]目标检测全过程(yolo环境配置+labelimg数据集标注+目标检测训练测试)

一、yolo环境配置 这篇帖子是我试过的&#xff0c;非常全&#xff0c;很详细【cudaanacondapytorchyolo(ultralytics)】 yolo环境配置 二、labelimg数据集标注 可以参考下面的帖子&#xff0c;不过可能会出现闪退的问题&#xff0c;安装我的流程来吧 2.1 labelimg安装 label…

Cursor配置MCP Server

一、什么是MCP MCP&#xff08;Model Context Protocol&#xff09;是由 Anthropic&#xff08; Claude 的那个公司&#xff09; 推出的开放标准协议&#xff0c;它为开发者提供了一个强大的工具&#xff0c;能够在数据源和 AI 驱动工具之间建立安全的双向连接。 举个好理解…

【开源免费】基于SpringBoot+Vue.JS新闻资讯系统(JAVA毕业设计)

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

CSDN年度评选揭晓,永洪科技AI技术与智能应用双星闪耀

近日&#xff0c;永洪科技在CSDN&#xff08;中国专业开发者社区&#xff09;的年度评选中&#xff0c;凭借在人工智能技术创新与vividime在行业应用中的卓越表现&#xff0c;一举斩获“人工智能企业”及“智能应用”双料大奖。这一荣誉不仅彰显了永洪科技在AI领域的领先地位&a…

利用three.js在Vue项目中展示重构的stl模型文件

一、目的 为了在前端页面展示3d打印机打印过程 二、前期准备 完整模型的stl文件和模型切割成的n个stl文件 models文件夹下的文件就是切割后的stl文件 三、代码 <template><div ref"threeContainer" class"three-container"></div><…

自动驾驶两个传感器之间的坐标系转换

有两种方式可以实现两个坐标系的转换。 车身坐标系下一个点p_car&#xff0c;需要转换到相机坐标系下&#xff0c;旋转矩阵R_car2Cam&#xff0c;平移矩阵T_car2Cam。点p_car在相机坐标系下记p_cam. 方法1&#xff1a;先旋转再平移 p_cam T_car2Cam * p_car T_car2Cam 需要注…

【卡牌——二分】

题目 分析 发现答案具有二分性&#xff0c;果断二分答案 代码 #include <bits/stdc.h> using namespace std; using ll long long;const int N 2e510;int n, a[N], li[N]; ll m;bool check(int x) {ll t m;for(int i 1; i < n; i){if(a[i] > x) continue; //…

< 自用文儿 > Gobuster 暴力扫描工具与 SecLists 安全测试词表集合

Ethice 道德问题 GFW 的保护下&#xff0c;很多的设备操作系统是停留在更老的版本&#xff0c;应用软件也是&#xff0c;因此很多的漏洞没有被修复。通讯没有使用加密&#xff0c;例如网页没有使用 HTTPS 网站很多。几乎是半裸的在网络上等着被食。 不做恶是下限。 环境&…

java后端开发day23--面向对象进阶(四)--抽象类、接口、内部类

&#xff08;以下内容全部来自上述课程&#xff09; 1.抽象类 父类定义抽象方法后&#xff0c;子类的方法就必须重写&#xff0c;抽象方法在的类就是抽象类。 1.定义 抽象方法 将共性的行为&#xff08;方法&#xff09;抽取到父类之后。由于每一个子类执行的内容是不一样…

AI数据分析:用DeepSeek做数据清洗

在当今数据驱动的时代&#xff0c;数据分析已成为企业和个人决策的重要工具。随着人工智能技术的快速发展&#xff0c;AI 驱动的数据分析工具正在改变我们处理和分析数据的方式。本文将着重介绍如何使用 DeepSeek 进行数据清洗。 数据清洗是数据分析的基础&#xff0c;其目的是…

第2_3章_入门管理资源服务器

入门 对于某些应用程序&#xff0c;你可以参考以下资源&#xff0c;快速开始使用 Keycloak 授权服务&#xff1a; 在 Wildfly 中保护 JakartaEE 应用程序&#xff08;https://github.com/keycloak/keycloak-quickstarts/tree/latest/jakarta/servlet-authz-client&#xff09…

2025年如何实现安卓、iOS、鸿蒙跨平台开发

2025年如何实现安卓、iOS、鸿蒙跨平台开发 文章目录 2025年如何实现安卓、iOS、鸿蒙跨平台开发1. 使用统一开发框架2. 华为官方工具链支持3. 代码适配策略4. 生态兼容性处理5. 性能与体验优化总结&#xff1a;方案选择建议 本文首发地址 https://h89.cn/archives/324.html 最新…