01避免单片组件的策略
平衡单一责任与干核。
自下而上思考通常意味着拥抱构图模式。这通常意味着在消费点可能会有一些重复。
DRY是我们作为开发人员学习的第一件事,DRY代码感觉很好。但是,在使所有东西干燥之前,最好等待并查看是否需要它。
但是,这种方法可以让你随着项目的增长和需求的变化而“驾驭复杂性的浪潮”,并允许抽象的东西在有意义的时候更容易地使用。
控制反转
理解此原则的一个简单示例是回调和反转之间的区别。
使用回调,您不一定知道该函数将去哪里,调用多少次或调用什么。
Promise将控制权反转回给使用者,以便您可以开始编写逻辑并假装值已经存在。
在React的上下文中,我们可以看到这是通过组件API设计实现的。
我们可以通过来公开“槽”,或者渲染风格道具,在消费者端保持控制反转。
有时在这方面,人们不愿意控制上反转,因为有一种感觉,消费者将不得不做更多的工作。但这既是放弃可以预测未来的想法,也是选择赋予消费者灵活性。
第二个示例对不断变化的需求更加灵活,并且性能更高,因为不再需要是Button包中的依赖项。
您可以在此处看到自上而下与自下而上的细微差异。在第一个示例中,我们向下传递数据并让组件处理它。在第二个例子中,我们必须做更多的工作,但最终这是一种更灵活和高性能的方法。
同样有趣的是,它本身可以由引擎盖下的较小基元组成。有时,一个特定的抽象在下面有许多不同的子行为元素,这些元素可以明确化。
例如,我们可以将其进一步分解为适用于按钮和组件之类的东西,它们可以组合成诸如.这种更细粒度的细分通常留给设计系统库的领域,但作为以产品为中心的工程师,值得牢记。
开放以扩展
即使使用合成模式自下而上构建。您仍然需要使用可消费的API导出专用组件,但该组件由较小的基元构建而成。为了提高灵活性,您还可以从包中公开构成该专用组件的那些较小的构建块。
理想情况下,您的组件只做一件事。因此,在预制抽象的情况下,消费者可以采用他们需要的一件事,并将其包装起来,以使用自己的功能进行扩展。或者,他们可以只采用一些构成现有抽象的基元并构造他们需要的东西。
利用故事书驱动的开发
通常有大量的离散状态最终会在我们的组件中得到管理。代码库正变得越来越受欢迎,这是有充分理由的。
在使用故事书单独构建UI组件时,我们可以采用他们思维背后的模型,并为组件可能处于的每种类型的可能状态提供故事。
像这样预先执行此操作可以避免您意识到在生产中忘记实现良好的错误状态。
它还有助于确定构建到您正在处理的组件所需的所有子组件。
在单独构建UI组件时,您可能会问自己一些问题,这些问题会导致弹性组件以下是一些需要避免的更常见情况,这些情况会阻止构建弹性组件:
根据组件的实际用途命名组件。回到单一责任原则。如果长名字有意义,不要害怕。
命名一个组件也很容易比实际名称稍微通用一些。当事物的命名方式比它们实际执行的操作更通用时,它向其他开发人员表明,处理与X相关的所有内容的是抽象。
因此,当新需求出现时,它自然会脱颖而出,成为进行更改的明显位置。即使这样做可能没有意义。
避免使用包含实现详细信息的prop名称。特别是对于UI样式的“叶子”组件。尽可能地避免添加道具,例如某些内容与内部状态或域特定事物相关的位置。然后让该组件在传递该道具时执行其他操作。
如果需要执行此操作,则prop名称是否反映了它在使用它的组件的上下文中实际执行的操作会更清晰。
例如,如果道具最终控制了填充之类的东西,则道具名称应该反映这一点,而不是让组件知道看似不相关的东西。
小心通过道具进行配置。回到控制反转。
如果您知道自己只有一种类型的子项,那么像这样的组件可以正常工作(并且您肯定知道这绝对不会改变!),因为它们也可以安全地键入。
但正如我们所看到的,这是一种很难在试图快速交付的不同团队和开发人员之间扩展的模式。在实践中,对变化的弹性往往较差,并且往往复杂性迅速增长。
因为您通常最终希望扩展组件以具有不同或其他类型的子项。这意味着您将在这些配置选项或道具中添加更多内容,并添加分叉逻辑。
与其让使用者排列和传入对象,更灵活的方法是导出内部子组件,并让使用者编写和传递组件。
避免在呈现方法中定义组件。有时,在组件中具有“帮助程序”组件可能很常见。这些最终会在每次渲染中重新加载,并可能导致一些奇怪的错误。
此外,具有多个内部,方法往往是一种气味。这些通常是组件正在变得单一的标志,并且是分解的良好候选者。
02分解单片组件
如果可能的话,经常和尽早重构。识别可能发生变化的组件并积极分解它们是一个很好的策略,可以融入您的估计中。
当您发现自己处于前端变得过于复杂的情况下时,您会怎么做?
通常有两个选项:
重写内容并逐步迁移到新组件
逐步分解
目前,进入组件重构策略不在本指南的讨论范围之内。但是,您可以使用一堆经过实战检验的现有重构模式。
在像React这样的框架中,“组件”实际上只是伪装的函数。你可以用组件替换单词“函数”在所有现有的尝试和真正的重构技术中。
举几个相关的例子:
删除标志参数
将条件替换为多态性
上拉场
重命名变量
内联函数
03结语
我们在这里涵盖了很多领域。让我们回顾一下本指南的主要要点。
我们拥有的模型会影响我们在设计和构建前端组件时做出的许多微观决策。使这些明确是有用的,因为它们积累得非常快。这些决策的积累最终决定了什么成为可能-要么增加或减少添加新功能的摩擦,要么采用新的架构,使我们能够进一步扩展(不确定这一点或将其合并到下面)。
在构建组件时,自上而下与自下而上可能会在规模上产生截然不同的结果。在构建组件时,自上而下的心智模型通常是最直观的。在分解UI时,最常见的模型是在功能区域周围绘制框,然后这些区域成为您的组件。这种功能分解的过程是自上而下的,并且通常会导致立即创建具有特定抽象的专用组件。要求将发生变化。在几次迭代中,这些组件很容易迅速成为整体组件。
自上而下设计和构建可能会导致整体式组件。充满整体式组件的代码库会导致最终前端体系结构速度慢且无法适应更改。单片组件很糟糕,因为:
它们的更改和维护成本高昂。
他们有改变的风险。
很难跨团队利用现有工作。
他们表现不佳。
在采用面向未来的技术和架构时,它们会增加摩擦,这些技术和架构对于继续扩展前端非常重要,例如有效的代码拆分,跨团队的代码重用,加载阶段,渲染性能等。
通过了解底层模型和环境,我们可以避免创建整体组件,这些模型和环境通常会导致创建过早的抽象或它们的持续扩展。
React在设计组件时,可以更有效地采用自下而上的模型。这可以更有效地避免过早的抽象。这样我们就可以“驾驭复杂性的浪潮”,在时机成熟时抽象化。以这种方式构建为实现组件组合模式提供了更多的可能性。意识到整体式组件的成本有多高,我们可以应用标准的重构实践来定期分解它们,作为日常产品开发的一部分。