在众多项目中,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 代码?耦合通用组件与业务逻辑的更多相关文章

  1. 编写可维护的JavaScript代码(部分)

    平时使用的时VS来进行代码的书写,VS会自动的将代码格式化,所有写了这么久的JS代码,也没有注意到这些点.看了<编写可维护的javascript代码>之后,做了些笔记. var resul ...

  2. 一步步教你编写不可维护的 PHP 代码

    译者注:这是一篇很棒文章,使用有趣的叙述方式,从反面讲解了作为一个优秀的 PHP 工程师,有哪些事情是你不能做的.请注意哦,此篇文章罗列的行为,都是你要尽量避免的. 随着失业率越来越高,很多人意识到保 ...

  3. 编写可维护的js代码

    在工作中,制定一套统一的编码风格,可以提高开发效率,维护起来的也要容易很多,也能避免一些不必要的错误出现. 项目中常用的检查编码风格的工具JSLint.JSHint.JSCS.ESLint,,在这呢, ...

  4. 编写可维护的javascript代码--- 2015.11.22(注释)

    1.单行注释 // 这是一句单行注释 2.多行注释 /* 这里是代码 */     /*  这里都是注释 1232132  */      java的注释风格 /* * 另一段注释 * 这段注释包含2 ...

  5. 编写可维护的javascript代码--- 2015.11.21(基本格式化)

    1.1 每行的编码需要控制在80字符. 1.2 改用:的地方必须用上. 1.3 缩进用2个制表符,不过4个也可以. 1.4 当代码一行显示不全需要折行显示,这里我暂且假定缩进为4个字符. 1.5 如果 ...

  6. 编写可维护的javascript代码---开篇(介绍自动报错的插件)

    文章开篇主要推荐了2款检测编程风格的工具: JSLint和JSHint: jsLint是由Douglas Crockford创建的.这是一个通用的javascript代码质量检测工具,最开始JSLin ...

  7. 编写可维护的JavaScript代码

    1.  1)for-in循环用来遍历对象属性.不仅遍历对象的实例属性,还遍历从原型继承来的属性. 所以最好使用hasOwnProperty()方法来过滤. 2) for in循环遍历出的对象属性不能保 ...

  8. 翻译 | 玩转 React 表单 —— 受控组件详解

    原文地址:React.js Forms: Controlled Components 原文作者:Loren Stewart 译者:小 B0Y 校对者:珂珂君 本文涵盖以下受控组件: 文本输入框 数字输 ...

  9. 《代码不朽:编写可维护软件的10大要则(C#版)》读后感

    本书作者Joost Visser,译者张若飞.本书讲解了编写可维护代码的10个要则,从目录就可以看出这10点分别是: 编写短小的代码单元(15行以内,在大部分情况下还是能实现的,但是当我们使用Linq ...

  10. 如何编写可维护的面向对象JavaScript代码

    能够写出可维护的面向对象JavaScript代 码不仅可以节约金钱,还能让你很受欢迎.不信?有可能你自己或者其他什么人有一天会回来重用你的代码.如果能尽量让这个经历不那么痛苦,就可以节省不少时 间.地 ...

随机推荐

  1. 鸟类识别系统Python+Django+TensorFlow+卷积神经网络算法【完整代码】

    一.介绍 鸟类识别系统,使用Python作为主要开发语言,基于深度学习TensorFlow框架,搭建卷积神经网络算法.并通过对数据集进行训练,最后得到一个识别精度较高的模型.并基于Django框架,开 ...

  2. selenium元素定位---ElementNotInteractableException(元素不可交互异常)解决方法

    方法一: 增加强制等待时间 方法二: 使用js点击 element = self.browser.find_element(By.XPATH, "//td[@class='el-table_ ...

  3. Sentieon | 每周文献-Genetic Disease-第二期

    遗传病系列文章-1 标题(英文):Answer ALS, a large-scale resource for sporadic and familial ALS combining clinical ...

  4. 基于DirectX11+ImGui的Win32桌面程序开发

    一.常见图形界面框架(DirectUI.GUI) 1.题外话,纯属扯O 举两个常用的开发框架,MFC和Qt Widget里面每个控件都是Window,这是和DirectUI最大的区别.下面简单梳理下这 ...

  5. Federated Learning004

    联邦学习--笔记004 2023.03.13周一 快中期答辩了(3.20),最近甲流高发期 毕设期间,今天学习了联邦学习的一篇论文---Differentially Private Federated ...

  6. PB从入坑到放弃(五)窗口使用技巧

    PB应用程序就是由许多共同协作完成特定任务的窗口组成的集合. 窗口在应用程序的开发工作中占有很大的比重,是非常重要的一个 PB 对象 一.窗口类型 窗口类型 描述 Main ①可以覆盖其他窗口,也可以 ...

  7. 离线自动化部署CDH

    离线CDH集群自动化部署工具 离线CDH集群安装与部署的自动化脚本工具,简单支持「离线一键装机」. 脚本将对系统配置做出一定修改,使用前请务必确认当前服务器无其他人员.任务使用,以免造成不必要的麻烦, ...

  8. FAQ:zabbix 频繁丢失数据问题分析处理

    问题描述 在grafana上看到历史数据的绘图断断续续. 问题分析 1 性能瓶颈 一开始以为是哪里的性能遇到瓶颈,把服务器和zabbix的监控数据看了一遍,各个指标都没有问题. 2 上网百度 没有找到 ...

  9. Go函数可以返回多个值

    1 package main 2 3 import "fmt" 4 5 func swap(x, y string) (string, string){ 6 return y,x ...

  10. AcWing 4798. 打怪兽题解

    可以从 \(1\) 枚举到 \(n\) 表示要打多少个怪兽. 因为你要打 \(t\) 个怪兽,并不管顺序,所以我们可以对 \([1, t]\) 这一段进行排序,然后计算 \(a[t], a[t - 2 ...