写点什么

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

  • 2020-03-11
  • 本文字数:2818 字

    阅读完需:约 9 分钟

漫谈 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-03-11 22:191415

评论

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

Android Coder带你了解反射

子不语Any

后端 java; 10月月更

【Go实现】实践GoF的23种设计模式:访问者模式

元闰子

Go 设计模式 访问者模式

书单推荐|书籍是人类的良师益友

图灵社区

书单 教师节

开发者有话说|在刷怪升级的成长路上,技术人应该掌握的三个大招

迷彩

个人成长 10月月更 学会学习 学会提问 学会思考

书单推荐|书籍是人类的良师益友

图灵教育

书单 教师节

Vue3入门指北(十)侦听器

Augus

Vue3 10月月更

【牛客刷题-算法】NC141 判断是否为回文字符串

清风莫追

数据结构 算法 刷题笔记 10月月更

二本Java菜鸟9面字节遭虐,苦修数月深造这份 Java面试宝典,终进阿里

程序知音

Java java面试 程序员面试 后端技术 Java面试八股文

阿里P8面试官总结的《2022最新java面试题》,搞定90%以上的技术面

程序知音

Java 程序员面试 后端技术 Java面试题 Java面试八股文

【愚公系列】2022年10月 Go教学课程 020-Go容器之数组

愚公搬代码

10月月更

GitHub上的宝藏级SpringBoot核心文档,拿走不谢!

Geek_0c76c3

Java 数据库 开源 程序员 开发

【牛客刷题-算法】加精 _ 合并两个有序的链表 - 从思路设计、bug排除到最终实现的全过程

清风莫追

算法 链表 算法数据结构 10月月更

【C语言难点突破】指针的常见易错点

Geek_65222d

10月月更

微信业务架构图 & 学生管理系统方案

无语

「架构实战营」

高效编程不一定意味着要疯狂写代码

宇宙之一粟

程序员 10月月更

【Nacos源码之配置管理 三】TaskManager 任务管理的使用

石臻臻的杂货铺

nacos 10月月更

【结构体内功修炼】结构体实现位段(二)

Albert Edison

C语言 结构体 10月月更 位段

爬虫练习题(二)

张立梵

Python. 10月月更 爬虫案例

为什么大家偏爱怪异盒模型border-box?

茶无味的一天

CSS 前端 HTML5, CSS3

【牛客刷题-算法】NC151 最大公约数

清风莫追

数据结构 算法 最大公约数 10月月更

踩上元宇宙的风口后,消费级AR眼镜真的复兴了吗?

脑极体

【一Go到底】第六天---值类型、引用类型、标识符

指剑

Go golang 10月月更

pgsql数据库自动备份

衝鋒壹号

10月月更

2022-10-06:以下go语言代码输出什么?A:[1 2 3] [1 2 3] ;B:[1 2 3] [3 4 5]; C:[1 2 3] [3 4 5 6 7 8 9];D:[1 2 3] [3

福大大架构师每日一题

golang 福大大 选择题

Go设计模式“金旋风”——代理模式

Regan Yue

Go 设计模式 代理模式 10月月更

与学长共话成长,领跑毕业新未来

宇宙之一粟

校招 10月月更

浅谈中小企业如何正确选择网络营销模式

石头IT视角

在Chrome浏览器中最快速实现拾色器(颜色吸管)

茶无味的一天

前端 谷歌浏览器

Qt|使用QuaZip压缩包中文乱码问题解决

中国好公民st

c++ qt 10月月更

你不知道的Java工具类库,十倍提升开发效率

一灯架构

Java java面试 10月月更

【Nacos源码之配置管理 四】DumpService如何将配置文件全部Dump到磁盘中

石臻臻的杂货铺

nacos 10月月更

漫谈 React 组件库开发(二):组件库最佳实践_文化 & 方法_有赞技术_InfoQ精选文章