写点什么

漫谈 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:191518

评论

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

智慧building之一 智能家居

张老蔫

28天写作

全网独家首发!—份破解大厂面试官千层套路的算法+数据结构笔记!真是太TM重要了

比伯

Java 架构 面试 程序人生 算法

RocketMQ中的事务消息

废材姑娘

RocketMQ

LeetCode题解:105. 从前序与中序遍历序列构造二叉树,递归+数组切割,JavaScript,详细注释

Lee Chen

算法 大前端 LeetCode

城市生态的机器人革命

脑极体

案例研究之聊聊 QLExpress 源码 (五)

小诚信驿站

刘晓成 小诚信驿站 28天写作 QLExpress源码 聊聊源码

【小菜学网络】MAC地址详解

fasionchan

网络编程 网络协议 TCP/IP

Docker真的被Kubernetes放弃了吗?

蔡超

Docker Kubernetes 云原生

HBase 底层原理详解(深度好文,建议收藏)

五分钟学大数据

大数据 HBase

区块链未来三年内将广泛落地

CECBC

区块链

【计算机内功修炼】五:从小白到高手,你需要理解同步与异步

码农的荒岛求生

异步 同步 回调函数

精选算法面试-数组(二分查找)

李孟聊AI

面试 算法 数组 28天写作

28 天带你玩转 Kubernetes-- 第六天(玩转 Docker命令)

Java全栈封神

Docker k8s 28天写作 docker命令

量化交易系统开发软件源码

枪手博弈 - 在强者的世界,弱者的生存法则

石云升

博弈论 28天写作 枪手博弈

玩一玩Linux常见命令第二篇

程序员的时光

程序员 28天写作

【TF2系列笔记】Day01:在VSCode中创建开发环境

IT蜗壳-Tango

七日更 TF2

TRX智能合约系统开发案例详解

“直男”审美?不存在的!来看看 “攻城狮”对一款IoT App的UI改造吧!

IoT云工坊

android App 物联网 IoT sdk

Kubernetes介绍篇:是什么?为什么要用?

xcbeyond

Docker Kubernetes 容器 28天写作 Kubernetes从入门到精通

不要用+""代替强转

BerryMew

运维大规模ES集群的思考和实践

京东科技开发者

数据库 elasticsearch 数据分析

京东搜索排序在线学习的 Flink 优化实践

Apache Flink

flink

Spring Boot 中的MVC支持

武哥聊编程

Java mvc springboot SpringBoot 2 28天写作

工信部:推动区块链等与工业互联网的融合技术研究

CECBC

大数据

醒醒!Python已经支持中文变量名啦!

Python猫

Python

Spring 源码学习 14:initApplicationEventMulticaster、onRefresh 和 registerListeners

程序员小航

spring 源码 源码阅读

区块链:行业应用即将“引爆”

CECBC

区块链

【Mysql-InnoDB 系列】锁定读

程序员架构进阶

MySQL innodb 锁机制 28天写作

DevSecOps:好处和挑战

啸天

敏捷开发 运维自动化 DevSecOps 应用安全

三分钟快速掌握 maven插件

田维常

maven

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