写点什么

漫谈 React 组件库开发(二):组件库最佳实践

2020 年 3 月 11 日

漫谈 React 组件库开发(二):组件库最佳实践

一个系统拥有大量的业务场景和业务代码,相似的页面和代码层出不穷,如何管理和抽象这些相似的代码和模块,这肯定是诸多团队都会遇到的问题。不断的拷代码?还是抽象成 UI 组件或业务组件?显然后者更高效。


那么现在就面临一个选择:


一是选择 React 生态中已有的组件库,例如 antDesign、Material-UI 等比较成熟的组件库;


二是团队再开发一套属于自己的组件库。


有赞前端团队选择了后者,产出并开源了 Zent ,Zent 提供了一整套基础的 UI 组件以及常用的业务组件,目前我们有 45+ 组件,这些组件都已经在有赞的各类 PC 业务中广泛使用。本文我们就来聊一聊如何开发一套优秀的 React 组件库以及一套完整组件库的构成。


一、选择开源?还是自己造轮子?


React 大环境里面有很多优秀的 UI 组件库,国内比较有名的 antDesign,国外的 Material-UI,都是比较稳定和优秀的组件库。那么我们为什么还要自己去开发一套组件库呢?原因大致如下:


  • 有赞各个业务线 PC 产品有独立的设计规范,包括但不限于组件样式、交互模式。

  • 有赞微商城、零售、美业等 PC 产品的业务场景较为复杂,需要深度定制某些通用的组件,如 DesignSKU 组件。

  • 需要同时支撑有赞多个业务部门的 PC 产品。

  • 团队成员以开源的模式参与组件库的开发,期间会有很多互相的讨论、碰撞,本身也是对团队的锻炼过程。


二、组件库构成


构建一个完整的组件库需要考虑:


  • 组件设计思路

  • 组件代码规范

  • 组件开发流程

  • 组件测试

  • 组件维护(包括 PR / issue 管理、发包、文档)


1. 组件设计思路


组件是对一些具有相同业务场景和交互模式代码的抽象,组件库首先应该保证各个组件的视觉风格和交互规范保持一致, X 组件在 A 业务场景是一个交互,在 B 业务场景是另一个 UI 风格,这样就无法对 X 进行抽象,极大的增加了组件的构建成本。所以,设计组件之初,首先需要抽象和约定一套统一的视觉风格和交互规范。


其次,组件库的 props 定义需要具备足够的可扩展性,而且组件内部完全受控,保持组件具有统一的输入和输出,让我们来看一个 Button 的例子。


// Button is a react component of Zent<Button  type="primary"  className="customer-classname"  loading={true}  disabled={false}  size="large"  onClick={this.handleClick}>  {children}</Button>
复制代码


这是一个 Button 组件,我们定义了很多标记状态的 props,比如 type 表示 Button 的视觉风格,size 表示尺寸,disabled 禁用,loading 状态等,这些状态在组件内部都不会维护 state,所有的状态由传入的 props 来决定,自定义 className 方便我们做样式自定义,children 方便我们自定义 Button 的显示内容。


Button 甚至提供了 a标签的功能,只要在 Button 上传入 props:href。


// Button as <a><Button  type="primary"  className="customer-classname"  href="https://www.youzan.com"  target="_blank">  有赞首页</Button>
复制代码


我们需要做几个约定:


  1. 组件所有状态受控于 props

  2. 组件 children 支持自定义 Dom 结构

  3. 不要写死组件内部的 Dom 结构


2. 组件代码规范


有赞前端内部组件库,使用的是开源 lint 工具-- felint 。


felint 是一个集成了 eslint、stylelint、git hook 的前端代码检查工具。felint 为你的项目做以下三件事:


  • 初始化 eslint/stylelint 配置文件,无论是 react 项目、vue 项目、es5 还是 es6 都提供了针对性的配置方案

  • 安装 eslint/stylelint 及其依赖到当前项目的 node_modules 里

  • 挂载 git 钩子,在你提交代码时进行强制校验


具体使用可以参考官方 doc – felint 文档地址 。


3. 组件开发流程


约定好组件的设计思路和代码规范以后,接下来我们就可以参与开发组件了,组件库的基本开发流程,包括以下几点:


  • 组件初始化

  • 组件 Coding

  • 组件 Demo


Zent 里面有一个组件初始化命令: yarn new-component,这个命令完成了组件大部分初始化工作,包括自动创建组件需要的目录和模版代码,添加组件 js 和 css 代码。然后,我们就可以开始写组件代码,代码风格和规范严格按照 lint 的规范编写,如果不符合规范,是不能提交代码的。写完组件以后,需要写组件 Demo 并运行,方式是本地启动 server 来运行组件 Demo,这个可以组件作为组件的调试工具。


4. 组件测试


js 单元测试框架有很多,chai、jest、mocha、karma 等等,Zent 组件库使用的是 jest + enzyme 的组合,下面来看一个例子:


// Button UI testimport { mount } from 'enzyme';
describe('Button', () => { it('Button UI test', () => { const wrapper = mount(<Button>OK</Button>); expect(wrapper.hasClass('zent-btn')).toBe(true); expect(wrapper.text()).to.equal('OK'); });});
复制代码


使用 jest 做 UI 测试有局限性,只能测试基本的 dom 结构 和样式,一些逻辑交互无法测到,只能覆盖大部分的情况。 yarn test 用来执行测试脚本,测试结果会显示在终端。


5. 组件维护


组件日常维护占整个组件库生命周期的很大一部分,组件库做起来了以后,组件功能后续会不断迭代,也许是 bug fix,也可能是 new feature,这些组件的迭代我们通过 PR 和 issue 来管理,同时,我们需要管理好组件的 changelog。


总的来说,组件维护主要包括:PR / issue 的处理,发包和管理 changelog。


下面以 Zent 为例,来介绍一下 PR 规范。


PR 标题规则:[ bug fix / breaking change / new feature ] 组件名字:修改内容描述


  • 前面方括号用来区分 PR / issue 的类型:bug fix - 组件 bug 修复;breaking change - 不兼容的改动;new feature - 新功能

  • 修改内容尽可能言简意赅,总结 PR 的改动或者描述 issue

  • 描述请用中文

  • 组件名字请用英文,首字母大写


PR 用来生成 changelog,规范的 PR 有助于生成比较清晰的 changelog,一目了然,来看一下 Zent 的例子:



组件发包


组件发包只有拥有发包权限的人才能操作,Zent 是以组件库为单位发包的, yarn build 会将整个 Zent 的代码打包,使用命令 yarn publish 发包,在发包之前会跑组件测试,只有测试通过以后才能发包。


组件文档


一份好的 doc 是一个优秀组件库的标准,良好的文档能够提升组件库的整体品质和好感度,愿意花时间好好写 doc 的团队,那么他们产出的组件库应该也不会差到哪去,组件库文档维护也是组件库生命周期里重要的一环,有时候你甚至需要做到中英文双语 doc。


这里附上 Zent 组件库的 doc 地址:Zent。


三、小结


在本文中,我们从组件的设计思路、编码规范、开发流程、测试、日常维护这五个方面阐述了如何构建一个 React 组件库,并且以 Zent 为例讲述了有赞是如何做的,任何一个组件库都需要的经过这个生命周期,但我们需要思考的是:如何营造一个良好的组件库生态环境? 我们需要想办法让更多的人参与其中,共同作为组件库的维护者,选择开源是为了给 React 生态环境做输出,在前端组件化已经成为了既定事实的今天,我们不需要重复的造轮子,而是需要在组件化方面尝试新的突破,脱离前端技术的束缚,站在工程师的高度去抽象自己手头的代码。组件化这条路上,我们还有很多事情要做,Zent 只是一个开始。


2020 年 3 月 11 日 22:19189

评论

发布
暂无评论
发现更多内容

ARTS打卡-04

Geek_yansheng25

架构师训练营 - 第 3 周学习总结

红了哟

如何搭建一个Hadoop集群

Rayjun

大数据 hadoop

架构师训练营第四周总结

hiqian

揭秘!中国人一定要知道的北斗卫星系统

程序那些事

北斗卫星 北斗系统 卫星定位 卫星授时 黑科技

势能造就下的互联网大厂程序员为什么去开滴滴了?

非著名程序员

程序员 程序人生 提升认知 程序员成长

iOS 动画 - 窗景篇(三·完结)

柯烂

ios swift 动画 移动互联网 动效

架构师训练营第四周作业

hiqian

那些会阻碍程序员成长的细节[3]

码闻强

程序员 职业规划 职业成长

学写PEP,参与Python语言的设计

早睡蟒

Python Python PEP PEP

疫情常态下区块链构建分布式数字身份

CECBC区块链专委会

疫情 区块链技术 分布式数字身份

JDBC 批量插入:MyBatis、PostgreSQL

羊八井

postgresql mybatis JDBC

区块链≠分布式账本,别再傻傻分不清

CECBC区块链专委会

区块链技术 高考 信息防篡改

架构师训练营 - 第 3 周命题作业

红了哟

Tapd 自定义字段+需求视图+报表,轻松研发管理

飞哥

极客时间,项目管理 项目管理

软件架构语录

hiqian

一群龙舟划手 “拍了拍” 你:端午节安康~

BonreeAPM

在以后的高校招生中,应用区块链技术,可以防、治冒名顶替吗?

CECBC区块链专委会

区块链技术 高考 信息防篡改

mysql字符匹配批量修改

毛佳伟🐳

MySQL

ARTS 第五周 6.21-6.28

我笔盒呢

重学 Java 设计模式:实战中介者模式「按照Mybatis原理手写ORM框架,给JDBC方式操作数据库增加中介者场景」

小傅哥

设计模式 小傅哥 代码优化 代码规范 中介者模式

架构师训练营:第四周第一节,互联网架构系统架构的演化

zcj

极客大学架构师训练营

游戏夜读 | 这是一款情绪游戏

game1night

Github仓库如何选择开源许可证

早睡蟒

GitHub 开源许可证 GitHub license

serverless之一:入门

毛佳伟🐳

Serverless

Week2:作业二

车小勺的男神

ARTS - Week 4

Khirye

ARTS 打卡计划 arts

玩转Java8中的 Stream 之从零认识 Stream

Java小咖秀

学习 stream java8 Java 面试 经验

ARTS 第四周 6.15-6.21

我笔盒呢

[深入理解Redis]读取RDB文件

老胡爱分享

redis 源码阅读

限频/限流的一些思考

i风语

Java redis 微服务 sentinel ratelimiter

飞猪Flutter技术演进及业务改造的实践与思考

飞猪Flutter技术演进及业务改造的实践与思考

漫谈 React 组件库开发(二):组件库最佳实践-InfoQ