前言

其实,最早触摸 Headless UI 是在上一年,可巧看到了一个十分前沿且优异的组件库 —- Chakra UI,这个组件库自身便是 Headless UI 的实践者,一起也是 CSS-IN-JS 的集大成者。

我当时看过之后,就对该理念产生了很大的兴趣,一起工作中也正好有机会实践(着手公司开源组件库大版别重构),因此对该理念也有必定的实践经验。

那么今天,也是想和咱们共享介绍下这项还算前沿的技能,另一方面是也算是个人的一份技能总结,这儿也期望感兴趣的小伙伴能够在谈论区讨论。

契机:React Hooks 的诞生

React Hooks 能够说是 Headless UI 得以完成的柱石,为什么这么说,这儿咱们首先聊聊 React Hooks。

React Hooks 是什么

咱们都知道,React Hooks 是在 V16.8 版别诞生了,是它让咱们的函数组件真实拥有了状况。如下图,咱们以数字累加这个功用举例,能够看到关于相同的功用,React Hooks 的写法相关于曩昔类组件的写法从代码上会削减一丢丢。

全新的 React 组件规划理念 Headless UI

但仅仅是由于如此才支撑它吗?

咱们要知道,在 React v16.8 之前,一般情况下,一般的 UI 烘托直接运用函数组件就好,需求运用 state 或许其他副作用之类功用时,才会运用类组件。

两者分工也算合理,那么 hooks 的诞生又是为何?仅仅是为函数组件赋能吗?从运用者的视点来说,这明显说不曩昔,徒增了学习本钱不说,还多了一个纠结选项(函数组件 vs 类组件)。

React Hooks 的含义

所以,工作并没有那么简略。咱们能够推断,关于 hooks 它必定解决一些“类组件存在的不足或痛点”,这儿就不卖关子,罗列 2 点:

  1. 状况逻辑在组件之间难以复用

在曩昔,状况逻辑的复用往往会选用高阶组件来完成。但劣势也十分明显,需求在原来的组件外再包裹一层父容器。 导致层级冗余,乃至嵌套地狱,引来了很多吐槽点:

  • 增着重试的难度
  • 拉低运转的功率

相信运用 Redux 的同学都知道,为了快速状况办理到组件的注入,会运用 connect 对组件进行包裹,可是跟着项目迭代,翻开 DevTools 检查时发现 DOM 往往臃肿不胜。

全新的 React 组件规划理念 Headless UI

  1. 杂乱组件变得难以了解和保护

杂乱组件自身就很杂乱,可是类组件让其变得更加难以了解和保护。比方:在一个生命周期函数中往往存在不相干的逻辑稠浊在一起,或许一组相干的逻辑涣散在不同的生命周期函数中,这儿分别举个比方:

  • componentWillReceiveProps 中往往写入不相干 props 更新烘托的判断逻辑,关于一次更新,往往会多出一些无效的履行,拉低履行功率
  • componentDidMount 中注册工作,在 componentWillUnmount 中卸载该工作,往往容易忘记乃至写出 bug。

长此以往咱们的代码只会变得糟糕难明。

全新的 React 组件规划理念 Headless UI

React Hooks 对组件开发的影响

经过 React Hooks,咱们能够把组件的状况逻辑抽离成自定义 hooks,相干的逻辑放在一个 Hook 里,不相干的拆分红不同的 hook,最终在组件需求时引入,从而完成状况逻辑在不同组件之间复用。

全新的 React 组件规划理念 Headless UI

正是由于 React Hooks 的诞生,使 Headless UI 组件在技能上成为或许,这也是它为什么最近才开端流行的原因。 所以,接下来咱们介绍下什么是 Headless UI。

什么是 HeadLess UI

Headless UI 的定义

Headless UI 现在社区还在探究实践阶段,这儿我对它做了个简略定义:Headless UI 一套根据 React Hooks 的组件开发规划理念,着重只担任组件的状况及交互逻辑,而不管标签和款式。 其本质思想其实便是重视点别离:将组件的“状况及交互逻辑”和“UI 展现层”完成解耦

Headless UI 组件

从实体上看,Headless UI 组件便是一个 React Hook。

全新的 React 组件规划理念 Headless UI

从表象上来看,Headless UI 组件其实便是一个什么也不烘托的组件。

全新的 React 组件规划理念 Headless UI

为什么会有 Headless UI

那么咱们为什么会需求一个啥也不烘托的组件呢?

这儿咱们仍是以数字加减这个功用举例,先思考规划完成一个数字加减器 Counter 组件。

传统版组件的规划痛点

依照传统的形式,咱们或许会直接去编写导出一个名字叫 Counter 组件,然后运用上直接烘托它即可,关于组件的功用经过 props 设置,比方非受控初始数字值。

全新的 React 组件规划理念 Headless UI

那么这么做有什么满意不了的痛点呢?咱们这儿随意举个场景,然后分别来从组件的运用者、保护者以及服务的产品三个视点来分析下。

1. 运用者 – 高定制事务场景怎样完成满意?

现在咱们事务有这样的诉求:左右两个加减按钮要求支撑长按后悬浮展现 Tooltip 提示。

全新的 React 组件规划理念 Headless UI

其实从产品视点这个需求很朴实,提高交互体验嘛。可是如果依照之前传统的组件规划,那就头疼了。它一整个都是组件库里边暴露出来的(假定哈),怎样去侵入到里边给加减按钮加 Tooltip 呢?

其实,关于组件这样定制事务场景的诉求,咱们一般解决思路或许是这样:

全新的 React 组件规划理念 Headless UI

可是跟着计划越往后挑选,咱们的代价是越来越高的,脸上的苦楚面具也越来越明显。

2. 保护者 – 组件 API 日趋杂乱,功用扩展 & 向下兼容的苦恼?

关于保护者而言,如果要去满意这样的诉求,那么他或许会这么做。

一开端,需求比较简略,咱们能够经过新增 API 动态注入要完成的功用,关于上面的诉求,咱们或许会新增 xxxButtonTooltipText 之类的 API 来完成 Tooltip 案牍的配置;

一周后,又需求加减按钮支撑 Icon 自定义,咱们或许会增加 xxxButtonText 之类的 API 来满意;

又过了 2 周,咱们又想支撑 Tooltip 展现方位配置,避免遮挡核心内容展现,咱们或许会增加 xxxButtonTooltipPlacement 。。。

日复一日,组件 API 数快速扩展,最终,保护者发现实在忍耐不了了,决议测验运用 Render Props 规划,以此一劳永逸,于是新增了 xxxButtonRender 支撑加减按钮自定义函数烘托。

全新的 React 组件规划理念 Headless UI

咱们发现,经过这么做,一个简略的组件变得日趋杂乱,不仅仅存在功用冗余完成,并且后边还要考虑功用扩展以及向下兼容,脸上的苦楚面具也逐步明显。

别的,关于运用者,当想运用一个组件发现有几页的 API 数量时,也会浅叹一声,功用难以检索到,并且大部分或许都不需求,面临性能优化也难以入手。

3. 产品:怎样快速打造好用定制的品牌 UI ?

关于一个产品,最重要的一点便是刻画产品自身的品牌形象和产品特征。关于用户最直接触摸的 UI 交互,那更是尤为重要。那么怎样快速打造好用定制的品牌 UI 呢?

仍是以数字加减器举例,那么,它的好用或许体现在它具备较为完善且好用的才能。

  • 点击加减按钮:数字加减步长
  • Accessibility 可拜访性
  • 数字值最大最小值控制
  • … …

关于它的定制,或许体现在它 UI 视图层上的差异化。如下图,仅仅是 Counter 这种小组件,就有五花八门的 UI 形状,更甭说其它更杂乱的组件了。

全新的 React 组件规划理念 Headless UI

Headless UI 的解法

从上面的分析咱们能够看到,UI 是一个自由度十分高的玩意,而构建 UI 又是一种十分品牌化和定制化的体验。

那么,咱们能不能只需复用组件的交互逻辑,布局和款式彻底自定义呢?明显,Headless UI 便是干这件工作的。

全新的 React 组件规划理念 Headless UI

关于 Headless UI 组件,咱们要做到第一件事,便是分析和抽离组件的状况以及交互逻辑。关于 Counter 组件,它的状况逻辑大致如下:

全新的 React 组件规划理念 Headless UI

咱们把这些状况逻辑收敛到一个叫 useCounter 的 React Hook 中。它接纳用户传入的功用 API 设置,然后返回一套已处理过的全新 API。

关于用户而言,咱们只需把返回的 API 赋予到想赋予的标签上,那么就得到了一个只带交互才能的无头组件。

全新的 React 组件规划理念 Headless UI

最终,咱们结合规划稿进行 UI 还原,对编写自定义款式,最终就能完成一个全新数字加减器组件了;

别的,咱们还能够将标签从头排版,然后款式改吧改吧,将按钮肯定定位一下,最终就能完成一个数字输入框组件;

除此之外,咱们还能够根据它封装,比方原本的最大值表明总页数,插入到标签中间,款式再改吧改吧,就能完成了一个迷你版的分页器组件了。

全新的 React 组件规划理念 Headless UI

能够看到,经过 Headless UI 的规划思路,咱们最终产出了一个叫 useCounter 的 React Hook,经过它,咱们不必关怀组件最为杂乱且最通用的部分—-交互逻辑,而是把它交给组件保护者办理;而关于经常改变需求定制的 UI 部分彻底由咱们自由发挥,从而完成最大化地满意事务高定制扩展的诉求,一起,也尽或许完成代码的充沛复用。

Headless UI 的优与劣

这儿咱们简略整理下 Headless UI 的优势和劣势,以及现在主张的适用场景,便利咱们做技能选型和学习。

优势

  • 有极强大的 UI 自定义发挥空间,支撑高定制扩展

能够看到 headless 的优势也十分明显,由于它更抽象,所以它拥有十分强大的定制扩展才能:支撑标签排版、元素组合,内容插入、款式定义等等都能满意。

  • 最大化代码复用,减小包体积

从上面能够看到,组件的状况逻辑能够尽或许到达最大化复用,帮助咱们减小包体积,增强全体可保护性。

  • 对单测编写友好

由于根本都是逻辑,关于工作回调、React 运转办理等都能够快速模仿完成单测编写和回归;而 UI 部分,一般容易改变,且不容易出 bug,能够避免测试。

劣势

  • 对开发者才能要求高,需求较强的组件抽象规划才能

抽象层次越高,编写难度越大。关于这样 headless 组件,咱们重视的组件 API 规划和交互逻辑抽离,这十分考验开发者的组件规划才能。

  • 运用本钱大,不主张简略事务场景下铺开运用

UI 层彻底自定义,存在必定开发本钱,因此需求评估好投入产出,关于没有特别高要求的 2b 事务的话,仍是主张运用 Ant Design 这样自带 UI 标准的组件库进行开发。

Headless UI 的生态与展望

社区生态

关于组件,现在在国外现已有些探究和实践的案例,比方 React-Popper、React-Hook-Form、TanStack-Table,三个是组件库“三大难”,它们 stars (均上万)和活跃度都十分高,未来根据 headless UI 规划实践的组件只会越来越多。

全新的 React 组件规划理念 Headless UI

关于组件库,我现在看到的比较不错的实践便是 Chakra-UI 组件库,整个组件库选用分层架构(这儿以数字输入框组件为例):

全新的 React 组件规划理念 Headless UI

  • 底层运用 Headless UI 那一套形式,对外暴露相关的 React Hook,保证整个组件的高定制扩展的诉求能得到最大化满意。

全新的 React 组件规划理念 Headless UI

  • 上层则提供了类似于 Ant Design 这样的组件,自带默认的 UI,但不同的是每个组件都是由颗粒度更小且必要的原子组件构成,能够直接引入它们运用,这样又保证大部分简略或一般的场景能够快速完成并满意。

留意:其实一个组件拆分红多个必要的原子组件构成,其实也算是 Headless UI 的一种实践形状,把交互逻辑生效的 API 直接绑定在必要的元素标签上,然后以原子组件暴露出来,标签的排版和款式修改也彻底能够由用户自定义。

全新的 React 组件规划理念 Headless UI

别的,在 React Next 2022 大会上,也有嘉宾共享介绍 Headless UI 相关的理念,整个社区现在都处在持续发酵的阶段。

全新的 React 组件规划理念 Headless UI

未来展望

个人认为 Headless UI 是未来 React 组件库底层的最佳实践。

关于组件库而言,或许咱们都不需求“读书学习”了,而是都运用同一套组件底层的状况以及交互逻辑,而在 UI 层以及细节上再进行品牌、场景定制化扩展。

全新的 React 组件规划理念 Headless UI

总结

那么,以上便是关于 headless 规划理念的全部内容。经过 Headless UI,咱们能够快速复用组件的状况以及交互逻辑,关于布局和款式完成彻底自定义

别的,Headless UI 是一个组件库规划的新思路,也是未来组件库必然的趋势。关于前端同学而言,学习了解它也显得尤为重要。

值得一提的是,在日常开发中,咱们也能够测验学习这样的思路,将通用状况逻辑抽离出去,便利复用,帮助咱们在日常开发提效。比方:常见的挑选过滤、分页请求列表数据的逻辑等;乃至,咱们还能够将事务逻辑同 UI 交互进行抽离,比方:在多端场景(Web PC 端、小程序端、RN 端)下复用同一套事务逻辑代码,完成事务逻辑复用和统一,以此大大提高咱们的生产力

参考

  • reactjs.org/docs/hooks-…
  • medium.com/@nirbenyair…

完结。

作者:不败花丶

Github:github.com/Flcwl