69

React 组件开发实践

 4 years ago
source link: https://www.tuicool.com/articles/eiMFFri
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

基于 React 的组件化开发方式,为富前端 web 应用提供大量技术实践,社区逐渐形成了稳定的组件规范,本文从 API 层面归纳出 6 种组件类型,分析其优缺点和适用场景,为日常组件开发提供一个方法指南。6 种类型分别为结构型组件、样式型组件、组合型组件、配置型组件、受控型组件、非受控组件。

结构型组件与样式型组件

jeYf2iR.png!web

结构型组件定义了组件大体结构,结构的具体实现由外部传递。样式型组件确定了组件结构细节,外部只需传递参数即可渲染预期样式。样式型组件是较为常用的组件类型,很少有开发者会根据一份设计稿来推断组件未来可能的改动,这也导致了样式型组件在复用性与拓展性上偏弱。对于比较通用的组件,例如 Button 按钮、Modal 弹框、Form 表单等,不应仅提供样式型实现,应该抽象出结构型组件。

这两种类型并不是非此即彼的关系,样式型组件固定的 API 参数可以降低使用成本,结构型组件弹性的 API 设定可以提供扩展性,结合两者的优点可以构造出既简单又可拓展的组件。关于两者结合的优势最具说服力的实践是通用组件库,结构型组件可显著降低业务方的沟通成本与接入风险,如下示意图演示了业务方与组件库之间的两种沟通模型:

样式型组件库与业务方的沟通模型

A3UnEju.png!web

结构型组件库与业务方的沟通模型

r6NfieQ.png!web

以上两种模型每一个箭头为一个工时,样式型组件库完成一次需求变更需要三个工时,业务方要等待组件库实现功能后才能进行下一步。结构型组件库给予业务方更多的自主性,不用等待组件库实现新特性,通过自定义结构满足当前需求,组件库有充足的时间分析需求是否通用,是否值得提供新 API,结构型组件在这个过程中扮演了缓冲区的角色,使得业务方与组件库可以并行协同开发,确保各自的研发效率与节奏。

组合型组件与配置型组件

BRZNJzf.png!web

组合型组件以 JSX 为主体,通过组件间的嵌套组合描述业务逻辑。配置型组件通过 props 传递数据结构,组件内部根据预先设定好的逻辑渲染视图。日常开发倾向于写配置型组件,组合型组件更多的出现在通用组件库中。

组合型组件结构清晰,扩展性高,组件使用者通过阅读 JSX 的 render 函数即可了解业务逻辑,但组件间联系微弱,ref 引用相互隔离,难以构建复杂的交互组件。配置型组件需要写的代码量少,但组件内部渲染处于黑箱,使用者难以理解组件逻辑,使其在拓展性上偏弱。比较基础的组件,例如 Form 表单,Select 选框等,建议采用组合型,有利于使用者组织业务代码,复杂交互组件可使用配置型。

组合型组件最具代表性的实践是 Ant Design,整个组件库的 API 设计严格遵循组合型优先原则,为同一组件的不同位面分别提供组合型结构,使其在拓展性和易用性上都达到了很高的水准。如下示意图演示了用两种组件类型开发 Select 选框的演化模型。

Select 简单选框,组合型与配置型,都能提供清晰易用的接口

EjU7BjE.png!web

比较复杂的 Select 选框组,组合型组件通过提供新的子组件,仍可保持简洁的 API 调用。配置型组件有两种实现方式:提供新的属性或者扩展原属性,两种方式都会产生一定认知成本。

fqyEvmI.png!web

对于需要自定义的 Select 选框组,组合型组件得益于 JSX 的嵌套结构,可以很从容的提供自定义 API。配置型组件实现同样的功能,需要再一次拓展属性配置。

J7JbEnQ.png!web

受控型组件与非受控组件

3qe6Zzb.png!web

这两种类型有另一种表述:无状态组件和有状态组件。受控型组件内部只负责展示,仅对外提供回调,以表达改变的期望,其最终行为完全由外部驱动。非受控组件由内部处理某些行为,并不强制外部状态同步。官方推荐输出无状态受控组件,但是有状态的组件在项目开发中仍是必要的。

受控型组件在自身层面规范了单向数据流,可以与其他数据层框架整合,但是开发一个复杂的受控型组件,开发者可能需要向外提供数不清的接口与回调。非受控组件较为智能,组件可以自主维护状态,但开发者常常因此懒于做状态同步,上层组件重新渲染时,非受控组件会丢失内部的状态,失忆,日常开发中大多数的 bug 因此而来。

我们经常会以内部是否拥有 state 来衡量一个受控型组件与非受控组件,但是完全遵守这条标准将很难提供一个简单易用的大型受控组件,所有状态都由外部控制,使用者需要写大量配置代码才能跑通一个大型组件,使用成本极高。官方提供的解决方案通过两者结合的方式来处理受控与易用的矛盾,如下示意图展示了一个 Input 组件可以接受的参数类型。

36fUZra.png!web

按照类型定义可推导出如下三种使用方式,分别对应一种受控型用法,和两种非受控用法。

mQr2Q3j.png!web

开发一个受控与非受控兼具的组件,对组件本身的开发与维护有更高的要求,其难度随组件本身复杂度的增加而增加。但是对组件使用者来说,这种两者兼具的组件最能适应快速开发与后期代码调优。任何有输入输出特性的组件(各种表单,配置 + 回调组件),都可参照上述类型定义提供 API。

总结

React 组件本质上是 JS 函数的另一种形态,一切与函数有关的思想都可以反映在组件里,每一种组件都有其适用场景,开发一个大型 Web 项目需要搭配使用不同类型的组件,如何做出合适搭配则需要长时间的开发积累,在真正的项目里寻找最优解。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK