>

Native中的运用,风格指南驱动开发

- 编辑:至尊游戏网站 -

Native中的运用,风格指南驱动开发

前端组件化开发方案及其在React Native中的运用

2017/02/18 · 基础技术 · React, 前端, 组件化

本文作者: 伯乐在线 - ThoughtWorks 。未经作者许可,禁止转载!
欢迎加入伯乐在线 专栏作者。

文/刘先宁

随着SPA,前后端分离的技术架构在业界越来越流行,前端(注:本文中的前端泛指所有的用户可接触的界面,包括桌面,移动端)需要管理的内容,承担的职责也越来越多。再加上移动互联网的火爆,及其带动的Mobile First风潮,各大公司也开始在前端投入更多的资源。

图片 1

这一切,使得业界对前端开发方案的思考上多了很多,以React框架为代表推动的组件化开发方案就是目前业界比较认可的方案,本文将和大家一起探讨一下组件化开发方案能给我们带来什么,以及如何在React Native项目的运用组件化开发方案

从“敏捷”下手

“今天,客户的UX又给我邮件了一版新的设计(PDF文件),改动不大,无非就是这个高度再调高点、那个宽度再调小些、这里用粗体、那边用18px的字体,可以参考以前做的手风琴组件的body部分,还有就是,顺便把手机版的样式截个图发过来?”

我:“能告诉我宽度和高度的具体值吗?那个手风琴组件可以在哪个页面找到?”

另一个开发告诉我:”先凭感觉做,然后再找UX面对面的按照要求一个个过。“

我:”好,面对面谈,总比邮件来回要快些。“

UX答复我:”面对面谈可能没有时间,你能先做一个粗略的版本吗?我先看看,然后给你反馈。等你做完所有的部分,我们再约个时间一起过”

即便心里在暗骂(等我做完了,你又跟我说这个不对,那个不对?)嘴上还是说了,“可以。”

然后,我问QA:“有测试环境可以部署我的新代码吗?没有完全做完,但是要给UX看效果。”

QA说:“有,但是部署完估计要1个多小时。”

我看了下时间,再过一个小时,客户UX就下班了,要得到他/她的反馈,估计得明天了!

当我把这个故事讲给别人听的时候,一般会得到两个回复:

  1. 哎呀,跟我们一样,痛苦的很
  2. 你们怎么这么不敏捷?

我无法否认这两个说法,很痛苦,也确实不够敏捷。但为我们提供了一点点线索——敏捷。

图片 2

敏捷宣言中强调:个体和互动高于流程和工具,工作的软件高于详尽的文档。

上面的故事很明显并不满足敏捷的价值观,邮件和截图绝对不可能代表“个体和互动”,一个需要部署一个小时才能看到页面效果的应用也谈不上“可工作的软件”。

一、为什么要采用组件化开发方案?

在讲怎么做之前,需要先看看为什么前端要采用组件化开发方案,作为一名程序员和咨询师,我清楚地知道凡是抛开问题谈方案都是耍流氓。那么在面对随着业务规模的增加,更多的业务功能推向前端,以及随之而来的开发团队扩张时,前端开发会遇到些什么样的问题呢?

怎么破?引入“在线风格指南”

针对当前的痛点,想要破,需要做到至少下面三点:

  • 独立前端开发工作,让它与后端逻辑解耦(俗称“前后端分离”)
  • 建立“可工作的软件”来展示前端开发结果
  • 组件化的设计和开发流程

看到这三点,明白人可能会立刻联想到一个大家耳熟能详的前端开发框架:Bootstrap。没错,它作为一个优秀的前端开发框架,确实满足上面的要求,有许多不错的网站都将Bootstrap作为网站的前端骨架。

Bootstrap有两个特质非常吸引人,优秀的特性和组件和漂亮的开发文档

不过,今天我们不谈Bootstrap框架,我想来聊聊这个漂亮的开发文档,俗称“在线风格指南”。

相信大家对“风格指南”都不陌生,主要分两类:静态风格指南和动态风格指南。

静态风格指南也就是我们常见的静态设计文档,比如,由设计师提供的PSD/PDF等文件,文档中包含:调色板,字体,按钮,链接等等。

图片 3

(medialoot上的一个样例)

动态风格指南,也称为Living Style Guide(“活的”风格指南或者在线风格指南),它是一个包含风格指南的Web站点,就像Bootstrap开发文档一样。

图片 4

在这里,我们需要引入的是“在线风格指南”,而不是Bootstrap,这里的不同点在于:

  • 角色变化,我们从“风格指南”的使用者,变成了是它的拥有者、开发者和使用者。
  • 用户变化,它不再是开发文档,现在用户是UX、前端开发和BA(业务分析),在UX和BA的眼中看到的文档即最新实现结果,在前端开发眼中看到的代码即设计。
  • 侧重不同,不仅仅是基础组件,也具有更加偏业务的大型组件。

1. 前端开发面临的问题

  1. 资源冗余:页面变得越来越多,页面的交互变得越来越复杂。在这种情况下,有些团队成员会根据功能写自己的CSS、JS,这会产生大量的新的CSS或JS文件,而这些文件中可能出现大量的重复逻辑;有些团队成员则会重用别人的逻辑,但是由于逻辑拆分的粒度差异,可能会为了依赖某个JS中的一个函数,需要加载整个模块,或者为了使用某个CSS中的部分样式依赖整个CSS文件,这导致了大量的资源冗余。
  2. 依赖关系不直观:当修改一个JS函数,或者某个CSS属性时,很多时候只能靠人力全局搜索来判断影响范围,这种做法不但慢,而且很容易出错。
  3. 项目的灵活性和可维护性差:因为项目中的交叉依赖太多,当出现技术方案变化时,无法做到渐进式的、有节奏地替换掉老的代码,只能一次性替换掉所有老代码,这极大地提升了技术方案升级的成本和风险。
  4. 新人进组上手难度大:新人进入项目后,需要了解整个项目的背景、技术栈等,才能或者说才敢开始工作。这在小项目中也许不是问题,但是在大型项目中,尤其是人员流动比较频繁的项目,则会对项目进度产生非常大的影响。
  5. 团队协同度不高:用户流程上页面间的依赖(比方说一个页面强依赖前一个页面的工作结果),以及技术方案上的一些相互依赖(比方说某个文件只能由某个团队修改)会导致无法发挥一个团队的全部效能,部分成员会出现等待空窗期,浪费团队效率。
  6. 测试难度大:整个项目中的逻辑拆分不清晰,过多且杂乱的相互依赖都显著拉升了自动化测试的难度。
  7. 沟通反馈慢:业务的要求,UX的设计都需要等到开发人员写完代码,整个项目编译部署后才能看到实际的效果,这个反馈周期太长,并且未来的任何一个小修改又需要重复这一整个流程。

为什么还要组件化的设计和开发?

组件化的做法在当前的场景下,似乎有点顺其自然,特别是有Bootstrap作为前车之鉴。

我想大家都知道,前端开发其实有一个通病,即大量的JS、CSS和其他资源文件(字体文件、图标、图片),在没有很好的管理控制下,很容易导致资源的冗余,依赖关系复杂度增加、维护性降低、导致之后的开发难度变大。

和后端语言开发不同,比如,Java有包管理和类的支持,有一些常见(或者约定俗成)的实现层次,如:Controller、Service、Repository等;有框架和语言特性带来的优势,比如IOC、AOP、注解、继承、接口等,合理利用能够让代码职责单一,模块高内聚低耦合,接口化,可重用,易于测试等等。

而Web前端开发,由于涉及到的内容较广,又不太可能完全具备后端语言的优秀特性。所以,更加需要开发人员具有优秀的设计和管理思想,比如:CSS的合理命名和管理、有效利用CSS预处理器、JavaScript的模块化、框架的特性(比如AngularJS的依赖注入,指令)、以及组件化等等。

组件化其实是大型软件开发中的一个共识,特别是前端,在没有统一标准的前提下,大家都在不断的造轮子,有无数的人倒了下去,又有无数勇士踩着前者的尸体冲上来。也许是因为它确实能够具有一些非常优秀的特性:单一的职责、资源的高内聚、独立的作用域、可独立的测试、接口的规范化、可重用、可组合等。

图片 5

2.组件化开发带来的好处

组件化开发的核心是“业务的归业务,组件的归组件”。即组件是一个个独立存在的模块,它需要具备如下的特征:

图片 6

(图片来自:

  • 职责单一而清晰:开发人员可以很容易了解该组件提供的能力。
  • 资源高内聚: 组件资源内部高内聚,组件资源完全由自身加载控制。
  • 作用域独立: 内部结构密封,不与全局或其他组件产生影响。
  • 接口规范化: 组件接口有统一规范。
  • 可相互组合: 组装整合成复杂组件,高阶组件等。
  • 独立清晰的生命周期管理:组件的加载、渲染、更新必须有清晰的、可控的路径。

而业务就是通过组合这一堆组件完成User Journey。下一节中,会详细描述采用组件化开发方案的团队是如何运作的。

在项目中分清楚组件和业务的关系,把系统的构建架构在组件化思想上可以:

  1. 降低整个系统的耦合度:在保持接口不变的情况下,我们可以把当前组件替换成不同的组件实现业务功能升级,比如把一个搜索框,换成一个日历组件。
  2. 提高可维护性:由于每个组件的职责单一,在系统中更容易被复用,所以对某个职责的修改只需要修改一处,就可获得系统的整体升级。独立的,小的组件代码的更易理解,维护起来也更容易。
  3. 降低上手难度:新成员只需要理解接口和职责即可开发组件代码,在不断的开发过程中再进一步理解和学习项目知识。另外,由于代码的影响范围仅限于组件内部,对项目的风险控制也非常有帮助,不会因为一次修改导致雪崩效应,影响整个团队的工作。
  4. 提升团队协同开发效率:通过对组件的拆分粒度控制来合理分配团队成员任务,让团队中每个人都能发挥所长,维护对应的组件,最大化团队开发效率。
  5. 便于自动化测试:由于组件除了接口外,完全是自治王国,甚至概念上,可以把组件当成一个函数,输入对应着输出,这让自动化测试变得简单。
  6. 更容易的自文档化:在组件之上,可以采用Living Style Guide的方式为项目的所有UI组件建立一个‘活’的文档,这个文档还可以成为业务,开发,UX之间的沟通桥梁。这是对‘代码即文档’的另一种诠释,巧妙的解决了程序员不爱写文档的问题。
  7. 方便调试:由于整个系统是通过组件组合起来的,在出现问题的时候,可以用排除法直接移除组件,或者根据报错的组件快速定位问题。另外,Living Style Guide除了作为沟通工具,还可以作为调试工具,帮助开发者调试UI组件。

我们项目的代码组织结构

从“风格指南”到“驱动开发”

总结一下前面的内容,“前后端分离”,“在线风格指南”,“组件化开发”,似乎我们只说到一些与开发相关的事情,其实不然。

“在线风格指南”被开发,UX、BA共享,合理的组件划分可以合理控制开发闭环,UX可以更快的看到设计实现的原型,提升团队成员沟通频率,BA可以方便的根据组件合理的编写Story(故事卡)。

当这三个角色都参与到这个过程当中时,我们就真正回到今天的正题“风格指南驱动开发”。

这是一个相当新的术语,但不是我发明的,如果要追溯的话,最早在公开场合中谈到这个概念的人应该是Nicole Sullivan,她在2014年9月的一次演讲《Components & SGDD》中提出(Nicole Sullivan目前在NPM这家公司,没错,就是那个NPM,做Product Manager & Design Manager)。

“风格指南驱动开发”尝试着:

  1. 让UX和前端开发更紧密的工作在一起,将设计与前端开发的工作闭环缩小,更快速的迭代产品原型。
  2. 将UI开发和业务系统分离开,业务系统不仅仅是指后端系统(不仅仅是前后端分离),也包括业务的Web系统。
  3. 让设计文档更加“灵活”,更加及时(up to date),更加一致(single source of truth)。
  4. 让前端资源管理更加规范,开发模式更加清晰。
  5. 让整个Web开发周期更加敏捷(Agile)。

它是一种前端开发和团队工作方式的实践。

二、组件化开发方案下,团队如何运作?

前面大致讲了下组件化开发可以给项目带来的好处,接下来聊一聊采用组件化开发方案的团队是应该如何运作?

在ThoughtWorks,我们把一个项目的生命周期分为如下几个阶段:

图片 7

组件化开发方案主要关注的是在迭代开发阶段的对团队效率的提升。 它主要从以下几个方面提升了开发效率:

工作流程 - 如何“驱动开发”?

图片 8

开发流程

怎么样的工作方式,才算“风格指南驱动开发”?其实,当团队拥有了“组件化的思想”和“在线风格指南”,“风格指南驱动开发”的整个过程其实是行云流水的,我简单描述一下:

1.挖掘到新的需求/特性

当新的需求出现时,UX开始进行页面设计,Living Style Guide会作为设计的参考文档。通常情况,设计师会查看已有的调色板、字体和其他基本元素或组件来组成新的页面布局。在组件化的思想和Living Style Guide的帮助下,BA和设计师都会尝试使用或者扩展现有的组件。

2.抽象成组件

一旦设计完成,BA、UX和开发会开始讨论如何把新的设计细分为独立的组件,哪些是已经存在可以重用的,哪些是新的需用新建或者扩展实现的。Living Style Guide作为桥梁帮助设计与开发进行沟通,促进双方的理解,确保实现的准确性。而抽象出来的组件,帮助BA划分任务和故事(Story),以便更加准确的估算“故事点”。

3.实现和文档化

此时,Living Style Guide是作为一个开发框架和设计试验场(playground)。

作为一个试验场(playground),允许你随时看到每一个开发出来的组件,作为开发框架,允许你快速开发,它和真正的产品实现完全隔离,这种隔离会鼓励你以更加抽象的方式创建组件,以便于让他们更容易被重用。

Living Style Guide的开发注重组件化的隔离和规范化的开发流程(套路清晰明了),我们常常会开发一些自动化的构建任务来帮助快速初始化一个组件需要的基本内容,只要开发人员对开发所需的前端技术栈有掌握,就能较快速的开发完成相应的组件。

而开发完成的组件在Living Style Guide中立刻变成“活的文档”,可以快速展示各种不同的组件应用场景,提供给UX和BA做审查(review)。

4.组件在产品应用中的热插拔

最后一步,就是将组件应用到真正的产品实现中(该产品代码应该是与Living Style Guide毫无关系的业务代码)。而对于Living Style Guide输出的结果,应该可以任意选择刚好满足需求所需要的组件,拥有足够的灵活性,才能实现它在产品应用代码中的热插拔。

如果还有第5步的话,那就是重复上面的4步,这就是“风格指南驱动开发”的完整流程。

1. 以架构层的组件复用降低工作量

在大型应用的后端开发中,为了分工、复用和可维护性,在架构层面将应用抽象为多个相对独立的模块的思想和方法都已经非常成熟和深入人心了。

但是在前端开发中,模块化的思想还是比较传统,开发者还是只有在需考虑复用时才会将某一部分做成组件,再加上当开发人员专注在不同界面开发上时,对于该界面上哪些部分可以重用缺乏关注,导致在多个界面上重复开发相同的UI功能,这不仅拉升了整个项目的工作量,还增加了项目后续的修改和维护成本。

在组件化开发方案下,团队在交付开始阶段就需要从架构层面对应用的UI进行模块化,团队会一起把需求分析阶段产生的原型中的每一个UI页面抽象为一颗组件树,UI页面自己本身上也是一个组件。如下图:

图片 9

通过上面的抽象之后,我们会发现大量的组件可以在多个UI界面上复用,而考虑到在前端项目中,构建各个UI界面占了80%以上的工作量,这样的抽象显著降低了项目的工作量,同时对后续的修改和维护也会大有裨益。

在这样的架构模式下,团队的运作方式就需要相应的发生改变:

  1. 工程化方面的支持,从目录结构的划分上对开发人员进行组件化思维的强调,区分基础组件,业务组件,页面组件的位置,职责,以及相互之间的依赖关系。
  2. 工作优先级的安排,在敏捷团队中,我们强调的是交付业务价值。而业务是由页面组件串联而成,在组件化的架构模式下,必然是先完成组件开发,再串联业务。所以在做迭代计划时,需要对团队开发组件的任务和串联业务的任务做一个清晰的优先级安排,以保证团队对业务价值的交付节奏。

留在最后的思考 - 它到底驱动了什么?

图片 10

作为好奇宝宝的你们和我,当读完这篇文章,应该仍然在思考,它到底驱动了什么?

也许你比较熟悉TDD和BDD,他们通过测试,驱动我们编写刚好满足测试和满足需求的实现,而测试反过来成为保护伞,在我们通过重构提升代码质量的同时,保证功能的安全性。

那么,“风格指南驱动开发”到底驱动了什么?也许,它驱动着我们尽最大可能去重新使用已有的组件(代码)和设计更通用的组件,也驱动着我们(开发、UX、BA)进行更加频繁的沟通,它驱动着BA(业务分析)书写更加合理的Story,也驱动开发进行更加合理的代码和资源的管理。


更多精彩洞见,请关注微信公众号:思特沃克

2.以组件的规范性保障项目设计的统一性

在前端开发中,因为CSS的灵活性,对于相同的UI要求(比如:布局上的靠右边框5个像素),就可能有上十种的CSS写法,开发人员的背景,经历的不同,很可能会选择不同的实现方法;甚至还有一些不成熟的项目,存在需求方直接给一个PDF文件的用户流程图界面,不给PSD的情况,所有的设计元素需要开发人员从图片中抓取,这更是会使得项目的样式写的五花八门。因为同样的UI设计在项目中存在多种写法,会导致很多问题,第一就是设计上可能存在不一致的情况;第二是UI设计发生修改时,出现需要多种修改方案的成本,甚至出现漏改某个样式导致bug的问题。

在组件化开发方案下,项目设计的统一性被上拉到组件层,由组件的统一性来保障。其实本来所有的业务UI设计就是组件为单位的,设计师不会说我要“黄色”,他们说得是我要“黄色的按钮……”。是开发者在实现过程中把UI设计下放到CSS样式上的,相比一个个,一组组的CSS属性,组件的整体性和可理解性都会更高。再加上组件的资源高内聚特性,在组件上对样式进行调整也会变得容易,其影响范围也更可控。

图片 11

在组件化开发方案下,为了保证UI设计的一致性,团队的运作需要:

  1. 定义基础设计元素,包括色号、字体、字号等,由UX决定所有的基础设计元素。
  2. 所有具体的UI组件设计必须通过这些基础设计元素组合而成,如果当前的基础设计元素不能满足需求,则需要和UX一起讨论增加基础设计元素。
  3. UI组件的验收需要UX参与。

3. 以组件的独立性和自治性提升团队协同效率

在前端开发时,存在一个典型的场景就是某个功能界面,距离启动界面有多个层级,按照传统开发方式,需要按照页面一页一页的开发,当前一个页面开发未完成时,无法开始下一个页面的开发,导致团队工作的并发度不够。另外,在团队中,开发人员的能力各有所长,而页面依赖降低了整个项目在任务安排上的灵活性,让我们无法按照团队成员的经验,强项来合理安排工作。这两项对团队协同度的影响最终会拉低团队的整体效率。

在组件化开发方案下,强调业务任务和组件任务的分离和协同。组件任务具有很强的独立性和自治性,即在接口定义清楚的情况下,完全可以抛开上下文进行开发。这类任务对外无任何依赖,再加上组件的职责单一性,其功能也很容易被开发者理解。

所以在安排任务上,组件任务可以非常灵活。而业务任务只需关注自己依赖的组件是否已经完成,一旦完成就马上进入Ready For Dev状态,以最高优先级等待下一位开发人员选取。

图片 12

在组件化开发方案下,为了提升团队协同效率,团队的运作需要:

  1. 把业务任务和组件任务拆开,组件的归组件,业务的归业务。
  2. 使用Jira,Mingle等团队管理工具管理好业务任务对组件任务的依赖,让团队可以容易地了解到每个业务价值的实现需要的完成的任务。
  3. Tech Lead需要加深对团队每个成员的了解,清楚的知道他们各自的强项,作为安排任务时的参考。
  4. 业务优先原则,一旦业务任务依赖的所有组件任务完成,业务任务马上进入最高优先级,团队以交付业务价值为最高优先级。
  5. 组件任务先于业务任务完成,未纳入业务流程前,团队需要Living Style Guide之类的工具帮助验收组件任务。

4.以组件的Living Style Guide平台降低团队沟通成本

在前端开发时,经常存在这样的沟通场景:

  • 开发人员和UX验证页面设计时,因为一些细微的差异对UI进行反复的小修改。
  • 开发人员和业务人员验证界面流程时,因为一些特别的需求对UI进行反复的小修改。
  • 开发人员想复用另一个组件,寻找该组件的开发人员了解该组件的设计和职责
  • 开发人员和QA一起验证某个公用组件改动对多个界面上的影响

当这样的沟通出现在上一小节的提到的场景,即组件出现在距离启动界面有多个层级的界面时,按照传统开发方式,UX和开发需要多次点击,有时甚至需要输入一些数据,最后才能到达想要的功能界面。没有或者无法搭建一个直观的平台满足这些需求,就会导致每一次的沟通改动就伴随着一次重复走的,很长的路径。使得团队的沟通成本激增,极大的降低了开发效率。

在组件化开发方案下, 因为组件的独立性,构建Living Style Guide平台变得非常简单,目前社区已经有了很多工具支持构建Living Style Guide平台(比如getstorybook)。

开发人员把组件以Demo的形式添加到Living Style Guide平台就行了,然后所有与UI组件的相关的沟通都以该平台为中心进行,因为开发对组件的修改会马上体现在平台上,再加上平台对组件的组织形式让所有人都可以很直接的访问到任何需要的组件,这样,UX和业务人员有任何要求,开发人员都可以快速修改,共同在平台上验证,这种“所见即所得”的沟通方式节省去了大量的沟通成本。

此外,该平台自带组件文档功能,团队成员可以从该平台上看到所有组件的UI,接口,降低了人员变动导致的组件上下文知识缺失,同时也降低了开发者之间对于组件的沟通需求。

图片 13

想要获得这些好处,团队的运作需要:

  1. 项目初期就搭建好Living Style Guide平台。
  2. 开发人员在完成组件之后必须添加Demo到平台,甚至根据该组件需要适应的场景,多添加几个Demo。这样一眼就可以看出不同场景下,该组件的样子。
  3. UX,业务人员通过平台验收组件,甚至可以在平台通过修改组件Props,探索性的测试在一些极端场景下组件的反应。

5. 对需求分析阶段的诉求和产品演进阶段的帮助

虽然需求分析阶段产品演进阶段不是组件化开发关注的重点,但是组件化开发的实施效果却和这两个阶段有关系,组件化方案需要需求分析阶段能够给出清晰的Domain数据结构,基础设计元素和界面原型,它们是组件化开发的基础。而对于产品演进阶段,组件化开发提供的两个重要特性则大大降低了产品演进的风险:

  • 低耦合的架构,让开发者清楚的知道自己的修改影响范围,降低演进风险。开发团队只需要根据新需求完成新的组件,或者替换掉已有组件就可以完成产品演进。
  • Living Style Guide的自文档能力,让你能够很容易的获得现有组件代码的信息,降低人员流动产生的上下文缺失对产品演进的风险。

三、组件化开发方案在React Native项目中的实施

前面已经详细讨论了为什么和如何做组件化开发方案,接下来,就以一个React Native项目为例,从代码级别看看组件化方案的实施。

1. 定义基础设计元素

在前面我们已经提到过,需求分析阶段需要产出基本的设计元素,在前端开发人员开始写代码之前需要把这部分基础设计元素添加到代码中。在React Native中,所有的CSS属性都被封装到了JS代码中,所以在React Native项目开发中,不再需要LESS,SCSS之类的动态样式语言,而且你可以使用JS语言的一切特性来帮助你组合样式,所以我们可以创建一个theme.js存放所有的基础设计元素,如果基础设计元素很多,也可以拆分位多个文件存放。

import { StyleSheet } from 'react-native'; module.exports = StyleSheet.create({ colors: {...}, fonts: {...}, layouts: {...}, borders: {...}, container: {...}, });

1
2
3
4
5
6
7
8
import { StyleSheet } from 'react-native';
module.exports = StyleSheet.create({  
        colors: {...},  
        fonts: {...},  
        layouts: {...},  
        borders: {...},  
        container: {...},
  });

然后,在写具体UI组件的styles,只需要引入该文件,按照JS的规则复用这些样式属性即可。

2.拆分组件树之Component,Page,Scene

在实现业务流程前,需要对项目的原型UI进行分解和分类,在React Native项目中,我把UI组件分为了四种类型:

  • Shared Component: 基础组件,Button,Label之类的大部分其它组件都会用到的基础组件
  • Feature Component: 业务组件,对应到某个业务流程的子组件,但其不对应路由, 他们通过各种组合形成了Pag组件。
  • Page: 与路由对应的Container组件,主要功能就是组合子组件,所有Page组件最好名字都以Page结尾,便于区分。
  • Scene: 应用状态和UI之间的连接器,严格意义上它不算UI组件,主要作用就是把应用的状态和Page组件绑定上,所有的Scene组件以Scene后缀结尾。

Component和Page组件都是Pure Component,只接收props,然后展示UI,响应事件。Component的Props由Page组件传递给它,Page组件的Props则是由Scene组件绑定过去。下面我们就以如下的这个页面为例来看看这几类组件各自的职责范围:

图片 14

(1)searchResultRowItem.js

export default function (rowData) { const {title, price_formatted, img_url, rowID, onPress} = rowData; const price = price_formatted.split(' ')[0]; return ( onPress(rowID)} testID={'property-' + rowID} underlayColor='#dddddd'> {price}{title} );}

1
2
3
4
5
6
7
8
9
10
export default function (rowData) {
    const {title, price_formatted,
            img_url, rowID, onPress} = rowData;
    const price = price_formatted.split(' ')[0];
    return (
         onPress(rowID)}
          testID={'property-' + rowID}
          underlayColor='#dddddd'>
          {price}{title}
  );}

(2)SearchResultsPage.js

import SearchResultRowItem from '../components/searchResultRowItem'; export default class SearchResultsPage extends Component { constructor(props) { super(props); const dataSource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1.guid !== r2.guid}); this.state = { dataSource: dataSource.cloneWithRows(this.props.properties), onRowPress: this.props.rowPressed, }; } renderRow(rowProps, sectionID, rowID) { return ; } render() { return ( ); }}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import SearchResultRowItem from '../components/searchResultRowItem';
export default class SearchResultsPage extends Component {
 
  constructor(props) {
    super(props);
    const dataSource = new ListView.DataSource({
      rowHasChanged: (r1, r2) => r1.guid !== r2.guid});
    this.state = {
      dataSource: dataSource.cloneWithRows(this.props.properties),
      onRowPress: this.props.rowPressed,
    };
  }
 
  renderRow(rowProps, sectionID, rowID) {
    return ;
  }
 
  render() {
    return (
      
    );
  }}

(3)SearchResultsScene.js

import SearchResults from '../components/searchResultsPage'; function mapStateToProps(state) { const {propertyReducer} = state; const {searchReducer:{properties}} = propertyReducer; return { properties, }; } function mapDispatchToProps(dispatch) { return { rowPressed: (propertyIndex) => { dispatch(PropertyActions.selectProperty(propertyIndex)); RouterActions.PropertyDetails(); } }; } module.exports = connect( mapStateToProps, mapDispatchToProps,)(SearchResults);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import SearchResults from '../components/searchResultsPage';
function mapStateToProps(state) {
  const {propertyReducer} = state;
  const {searchReducer:{properties}} = propertyReducer;
  return {
    properties,
  };
}
 
function mapDispatchToProps(dispatch) {
  return {
    rowPressed: (propertyIndex) => {
      dispatch(PropertyActions.selectProperty(propertyIndex));
      RouterActions.PropertyDetails();
    }
  };
}
 
module.exports = connect(
  mapStateToProps,
  mapDispatchToProps,)(SearchResults);

3.Living Style Guide

目前社区上,最好的支持React Native的Living Style Guide工具是getstorybook,关于如何使用getstorybook搭建React Native的Living Style Guide平台可以参见官方文档或者我的博客。

搭建好Living Style Guide平台后,就可以看到如下的界面:

图片 15

接下来的工作就是不断在往该平台添加UI组件的Demo。向storybook中添加Demo非常简单,下面就是一个关于SearchPage的Demo:

import React from 'react'; import {storiesOf, action} from '@kadira/react-native-storybook'; import SearchPage from '../../../../src/property/components/searchPage'; storiesOf('Property', module) .add('SearchPage', () => ( ));

1
2
3
4
5
6
7
import React from 'react';
import {storiesOf, action} from '@kadira/react-native-storybook';
import SearchPage from '../../../../src/property/components/searchPage';
storiesOf('Property', module)
  .add('SearchPage', () => (
    
));

从上面的代码可以看出,只需要简单的三步就可以完成一个UI组件的Demo:

  1. import要做Demo的UI组件。
  2. storiesOf定义了一个组件目录。
  3. add添加Demo。

在构建项目的storybook时,一些可以帮助我们更有效的开发Demo小Tips:

  1. 尽可能的把目录结构与源代码结构保持一致。
  2. 一个UI组件对应一个Demo文件,保持Demo代码的独立性和灵活性,可以为一个组件添加多个Demo,这样一眼就可以看到多个场景下的Demo状态。
  3. Demo命名以UI组件名加上Demo缀。
  4. 在组件参数复杂的场景下,可以单独提供一个fakeData的目录用于存放重用的UI组件Props数据。

4.一个完整的业务开发流程

在完成了上面三个步骤后,一个完整的React Native业务开发流程可简单分为如下几步:

  1. 使用基础设计元素构建基础组件,通过Living Style Guide验收。
  2. 使用基础组件组合业务组件,通过Living Style Guide验收。
  3. 使用业务组件组合Page组件,通过Living Style Guide验收。
  4. 使用Scene把Page组件的和应用的状态关联起来。
  5. 使用Router把多个Scene串联起来,完成业务流程。

四、总结

随着前后端分离架构成为主流,越来越多的业务逻辑被推向前端,再加上用户对于体验的更高要求,前端的复杂性在一步一步的拔高。对前端复杂性的管理就显得越来越重要了。经过前端的各种框架,工具的推动,在前端工程化实践方面我们已经迈进了很多。而组件化开发就是笔者觉得其中比较好的一个方向,因为它不仅关注了当前的项目交付,还指导了团队的运作,帮助了后期的演进,甚至在程序员最讨厌的写文档的方面也给出了一个巧妙的解法。希望对该方法感兴趣的同学一起研究,改进。

1 赞 收藏 评论

关于作者:ThoughtWorks

图片 16

ThoughtWorks是一家全球IT咨询公司,追求卓越软件质量,致力于科技驱动商业变革。擅长构建定制化软件产品,帮助客户快速将概念转化为价值。同时为客户提供用户体验设计、技术战略咨询、组织转型等咨询服务。 个人主页 · 我的文章 · 84 ·   

图片 17

本文由设计建站发布,转载请注明来源:Native中的运用,风格指南驱动开发