如何编写难以维护的 React 代码?耦合通用组件与业务逻辑
在众多项目中,React代码的维护经常变得棘手。其中一个常见问题是:将业务逻辑直接嵌入通用组件中,导致通用组件与业务逻辑紧密耦合,使其失去“通用性”。这种做法使通用组件过于依赖具体业务逻辑,导致代码难以维护和扩展。
示例:屎山是如何逐步堆积的
让我们看一个例子:我们在业务组件 PageA 和 PageB 中都使用了通用组件 Card。
function PageA() {
return (
<>
{/* ... */}
{listA.map(({ title, content }) => <Card title={title} content={content} />)}
</>
)
}
function PageB() {
return (
<>
{/* ... */}
{listB.map(({ title, content }) => <Card title={title} content={content} />)}
</>
)
}
function Card({ title, content }) {
return (
<div>
<Title>{title}</Title>
<Content>{content}</Content>
</div>
)
}
某一天,出现了一个新需求:在手机端的所有页面都需要显示 Footer。于是,代码被修改如下:
function PageA({ isMobile }) {
return (
<>
{/* ... */}
{listA.map(({ title, content }) => (
<Card title={title} content={content} isMobile={isMobile} />
))}
</>
)
}
function PageB({ isMobile }) {
return (
<>
{/* ... */}
{listB.map(({ title, content }) => (
<Card title={title} content={content} isMobile={isMobile} />
))}
</>
)
}
function Card({ title, content, isMobile }) {
return (
<div>
<Title>{title}</Title>
<Content>{content}</Content>
{isMobile && <Footer />}
</div>
)
}
随后的某一天,小张接手了这个项目,又有新需求:只有第偶数个 Card 才应该显示 Footer。于是,秉承着最小影响范围的原则,代码被改成了这样:
function PageA({ isMobile }) {
return (
<>
{/* ... */}
{listA.map(({ title, content }, index) => (
<Card title={title} content={content} isMobile={isMobile} index={index} />)
)}
</>
)
}
function PageB({ isMobile }) {
return (
<>
{/* ... */}
{listB.map(({ title, content }, index) => (
<Card title={title} content={content} isMobile={isMobile} index={index} />)
)}
</>
)
}
function Card({ title, content, isMobile, index }) {
return (
<div>
<Title>{title}</Title>
<Content>{content}</Content>
{isMobile && index % 2 === 1 && <Footer />}
</div>
)
}
随后的某一天,小王接手了这个项目,又有新需求。秉承着最小影响范围的原则 ......
分析原因
乍看之下,每次修改都是“局部最优”的,尽量修改最少的代码以限制影响范围,以确保在添加新功能时不引入错误。然而,实际上,由于每次“偷懒”,我们都违反了原则,导致代码变得越来越混乱。
原则
分离关注点原则(Separation of Concerns)是计算机科学和软件工程的基本设计原则之一,旨在帮助程序员更好地组织和管理复杂的系统。该原则的核心思想是将大型系统或程序分解为多个互相独立的组件,每个组件负责解决特定的关注点或任务,而不会受到其他关注点的干扰。这有助于提高代码的可维护性、可扩展性和可重用性。
重构
将上述原则应用于这个示例中:通用组件应该只了解与自身相关的信息,Card 组件只关心何时显示 Footer,而不关心它在何处使用以及是否为第偶数个。让我们重构代码:
function PageA({ isMobile }) {
return (
<>
{/* ... */}
{listA.map(({ title, content }, index) => (
<Card title={title} content={content} showFooter={isMobile && index % 2 === 1} />)
)}
</>
)
}
function PageB({ isMobile }) {
return (
<>
{/* ... */}
{listB.map(({ title, content }, index) => (
<Card title={title} content={content} showFooter={isMobile && index % 2 === 1} />)
)}
</>
)
}
function Card({ title, content, showFooter }) {
return (
<div>
<Title>{title}</Title>
<Content>{content}</Content>
{showFooter && <Footer />}
</div>
)
}
通过这次重构,我们成功解耦了通用组件和业务逻辑,使代码更易于维护和扩展。
如何编写难以维护的 React 代码?耦合通用组件与业务逻辑的更多相关文章
- 编写可维护的JavaScript代码(部分)
平时使用的时VS来进行代码的书写,VS会自动的将代码格式化,所有写了这么久的JS代码,也没有注意到这些点.看了<编写可维护的javascript代码>之后,做了些笔记. var resul ...
- 一步步教你编写不可维护的 PHP 代码
译者注:这是一篇很棒文章,使用有趣的叙述方式,从反面讲解了作为一个优秀的 PHP 工程师,有哪些事情是你不能做的.请注意哦,此篇文章罗列的行为,都是你要尽量避免的. 随着失业率越来越高,很多人意识到保 ...
- 编写可维护的js代码
在工作中,制定一套统一的编码风格,可以提高开发效率,维护起来的也要容易很多,也能避免一些不必要的错误出现. 项目中常用的检查编码风格的工具JSLint.JSHint.JSCS.ESLint,,在这呢, ...
- 编写可维护的javascript代码--- 2015.11.22(注释)
1.单行注释 // 这是一句单行注释 2.多行注释 /* 这里是代码 */ /* 这里都是注释 1232132 */ java的注释风格 /* * 另一段注释 * 这段注释包含2 ...
- 编写可维护的javascript代码--- 2015.11.21(基本格式化)
1.1 每行的编码需要控制在80字符. 1.2 改用:的地方必须用上. 1.3 缩进用2个制表符,不过4个也可以. 1.4 当代码一行显示不全需要折行显示,这里我暂且假定缩进为4个字符. 1.5 如果 ...
- 编写可维护的javascript代码---开篇(介绍自动报错的插件)
文章开篇主要推荐了2款检测编程风格的工具: JSLint和JSHint: jsLint是由Douglas Crockford创建的.这是一个通用的javascript代码质量检测工具,最开始JSLin ...
- 编写可维护的JavaScript代码
1. 1)for-in循环用来遍历对象属性.不仅遍历对象的实例属性,还遍历从原型继承来的属性. 所以最好使用hasOwnProperty()方法来过滤. 2) for in循环遍历出的对象属性不能保 ...
- 翻译 | 玩转 React 表单 —— 受控组件详解
原文地址:React.js Forms: Controlled Components 原文作者:Loren Stewart 译者:小 B0Y 校对者:珂珂君 本文涵盖以下受控组件: 文本输入框 数字输 ...
- 《代码不朽:编写可维护软件的10大要则(C#版)》读后感
本书作者Joost Visser,译者张若飞.本书讲解了编写可维护代码的10个要则,从目录就可以看出这10点分别是: 编写短小的代码单元(15行以内,在大部分情况下还是能实现的,但是当我们使用Linq ...
- 如何编写可维护的面向对象JavaScript代码
能够写出可维护的面向对象JavaScript代 码不仅可以节约金钱,还能让你很受欢迎.不信?有可能你自己或者其他什么人有一天会回来重用你的代码.如果能尽量让这个经历不那么痛苦,就可以节省不少时 间.地 ...
随机推荐
- 为什么要重写equals要重写hashcode方法
Java 比较(==, equals) 一.= = ==:比较两个对象的引用是否是同一个地址 二.equals object中equals方法调用的就是==,可以在其他类中重写该方法. 三.为什么要重 ...
- Java 使用ArrayList获取10个1-20之间的随机数,要求不能重复
代码如下: public static void main(String[] args) { List<Integer> nums = new ArrayList<Integer&g ...
- 前端Vue组件之仿京东拼多多领取优惠券弹出框popup 可用于电商商品详情领券场景使用
随着技术的发展,开发的复杂度也越来越高,传统开发方式将一个系统做成了整块应用,经常出现的情况就是一个小小的改动或者一个小功能的增加可能会引起整体逻辑的修改,造成牵一发而动全身.通过组件化开发,可以有效 ...
- 前端Vue自定义开屏启动广告组件,点击广告图跳转广告详情
随着技术的发展,开发的复杂度也越来越高,传统开发方式将一个系统做成了整块应用,经常出现的情况就是一个小小的改动或者一个小功能的增加可能会引起整体逻辑的修改,造成牵一发而动全身. 通过组件化开发,可以有 ...
- Semantic Kernel Java SDK,为Java应用程序提供AI功能集成
美国时间 2023 年 7 月 19 日,Semantic Kernel 团队在其官方博客[1]上宣布发布 Java 版Semantic Kernel. Samantic Kernel系列的源代码可在 ...
- Linux 中设备的分类及网络设备接口路径
设备分类 字符设备 块设备 网络设备 参考文档: 手把手教Linux驱动 网络设备位置 [root@localhost ~]# cd /sys/class/net/ [root@localhost n ...
- Unity UGUI的PointerEventData的介绍及使用
Unity UGUI的PointerEventData的介绍及使用 1. 什么是PointerEventData? PointerEventData是Unity中UGUI系统中的一个重要组件,用于处理 ...
- redis的一些简单操作(针对key)
redis默认16个数据,默认使用0号 select为切换数据库的关键字 select 1 切换数据库 设置值 set k1 lucy key为 k1 value 为 lucy 查看全 ...
- Flutter系列文章-Flutter进阶2
这一节我将再详细地为您介绍 Flutter 进阶主题,包括导航和路由.状态管理.异步处理.HTTP请求和Rest API,以及数据持久化.让我们逐个介绍这些主题. 1.导航和路由 在 Flutter ...
- Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-install-4_w0c665/PyQt5/
错误: 解决方式:输入一下命令 1 pip3 install --upgrade setuptools 2 python3 -m pip install --upgrade pip 输入命令: 1 p ...