此文已由作者黄锴授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。

组件设计,从简单来看,就是如何提高编码效率,提高代码的复用率的方法,从高级来看,这是一门程序设计的艺术

最近看了redux作者——Dan Abramov写的《Presentational and Container Components》 感觉受益匪浅,发现有很多人都在讨论组件模式,作为一个每次写需求就抓耳挠腮的思考如何组织代码结构的人来说,如何更好的在工作中使用设计和使用组件,这确实是一个值得讨论的问题。

注:本文图片部分参考于Michael Chan 做的有关React component patterns的演讲: React component patterns, 有兴趣的童鞋可以去看看。

前言

组合模式

首先,我们先从宏观的角度来聊聊组件。

现在很多人现在都在谈设计模式,设计模式。什么是设计模式?设计模式主要是指GoF(四人组)《设计模式》一书中提出了23种设计模式,这23种设计模式被广泛应用在软件工程中,代表着最佳的实践方案。而在这些模式中,专门有一个设计模式叫:组合模式(Composite pattern),根据wikipedia的解释:

组合模式的目的是将对象组合成树型结构来表示部分-整体(part-whole)的层次结构。

组合模式使得用户对单个对象和组合对象的使用具有一致性。

它有以下优点

  • 可扩展性强:由于组件间是充分解耦的,你可以轻松的更新,替换组件

  • 编码高效:由于把功能拆解开,你可以专注于每个子模块功能的实现。

javascript中的组合模式——组件

如果你在现在的工作中使用了框架,你会发现,这些框架基本都使用了组合模式这种设计模式。例如Vue和React的Components,它允许你编写小的组件,然后通过他们的组合构建出你的实际应用。

在学校,总被老师说,要有大局观,大局观。使用组合模式,就可以很好的锻炼你的大局观。 这里我觉得云谦前辈 说的很贴切:

要记得,接到需求的第一步永远不是写代码,而是想清楚你要做什么,以上帝模式做整体设计。

开启上帝视角

接下来,就让我们在我们的编程世界扮演一个上帝(准确来说是女挖),看看我们这个充满组件世界到底发生了什么。

组件的诞生

在框架类的语言中,组件就是我们操作的基本单位,React对组件的操作提供了很多实用的API,一个组件就是通过使用这些API,产生了强大的生命力,你可以把它看作一个功能完善的细胞或者个体,我们所有的APP都是由这一个个细胞(个体)构成的。

然后,你在日常使用中会发现,有些组件,它总是使用其中的一部分API,有些组件经常使用另一部分API。说明这些组件开始有了自己的思考,产生了差异化(你可以把它看作基因突变)。当这些差异化越来越多,我们发现,这些组件因为各自的能力偏好,逐减组成了不同的阵营:

对于组件的阵营分类,有很多的说法:

  • 胖和瘦( Fat and Skinny,)组件

  • 状态和无状态/纯(Stateful and Stateless/pure)组件

  • 聪明和愚笨(Smart and Dumb)组件

  • 容器和展示( Container and Presentational )组件……

他们本质上都差不多,这里我们选用Redux作者Dan Abramov对组件的称法,叫他们容器展示组件,这里使用Container和Components

组件分好了阵营,就要开始制定标准,正所谓无规矩不成方圆,一个良好的组织对确定他们统一的旗号,核心价值观,才能方便后续找到更多的同类人,发展壮大。

组件的阵营

容器组件(Container)阵营

他们称自己是统治者,这里汇聚的都是精英份子,它们习惯管理和组织。作为高高在上的管理者,能让下属去做的事情自己一定不会动手。

因此他们制定了一套符合他们价值观的标准:

  • 代表结构:我只关心事情如何运作的,而不关心它是 如何表现的

  • 无样式:我这里除了一些包装div,基本没有其他标签,并且从不具有任何样式

  • 有状态:我掌握着核心数据,剩下的事情你们去做

  • 通常由其他组件生成:我们通常代表更高等的智慧(一般使用更高阶的组件生成)

  • 代表人物:各种Page页面,路由页面

展示组件(Components)阵营

他们通常由蓝白领组成,代表这着广大的工人阶层,什么脏活累活都是他们做,他们通常没有太多想法,只是想简单的做好自己的工作,少背锅就好。

在这里,每个组件关心的事情很少,他们的志向只是做好本质工作,因此他们制定了一套符合他们工作习惯的标准:

  • 代表渲染:关注事物的外观

  • 有样式:基本上dom的渲染和样式这些脏活累活都在这里干。

  • 强调独立(很重要): 我们彼此分工明确,不依赖于应用程序的其余部分(例如Flux操作或Store)。

  • 不关心数据:我们不关心数据怎么产生的,不要在我们这里指定数据的加载方式或变更方式。

  • 接受传回指令:仅通过props接收数据和回调。

  • 弱状态:我们基本不需要有自己的状态(当我们这样做时,它是UI状态而不是数据)。

  • 代表人物:Search,SiderBar,UserList,Pagintation

这两种阵营基本是完全独立的,由于这种良好的划分,他们在社会中能很好的相处(蓝色是展示组件,灰色是容器组件。

实际运行

好了,看他们风风火火的把阵营分了,得给他们找点事干,看这个社会分工的实际运行效果怎么样。

这里顺便提一句React的组件定义,通常有两种方式类定义和无状态函数定义

无状态函数定义:

这样的好处是它本身是独立的,没有状态的,它只会根据传入的props(可以考虑成指令)来修改自己的显示,这样的组件就具备很好的通用性,而且修改起来也方便,不用担心会影响到别的组件。

var User = ({name}) => (  <span>{name}  </span>);

类定义:

如果有些内置的状态需要维护,或者需要使用生命周期,可以使用类定义的方式。

class User extends Component {constructor(props) {super(props);    this.state = {name: props.name,editable: false,};} render(){     return ...}
}

容器组件——定义结构,下发指令

容器组件可以通过类定义,因为可能会使用到生命周期钩子(使用dva也可能无需生命周期钩子)。

如果使用了redux类的状态管理机制,一般就会由connect生成(Relay的createContainer(),或Flux Utils的Container.create())。

我们现在要做一个用户页面,我们把这个任务布置下去,有一个容器阵营拿到了这个页面制作指标,然后这些精英开始做组织架构工作,他们觉得完成这个工作需要造三个组件:UserSearchUserListUserModal。然后每个组件需要的处理的指令(数据)也写好了,放在userXXXProps里,好了,他们的任务完成,开始去找展示容器阵营的人去实现这些功能。

function Users({ users }) {  // 从Redux里获取数据const {loading,list,total,current,} = users;  // 下发任务const userSearchProps = {};  const userListProps = {};  const userModalProps = {};  // 整体结构设计return (    <div><UserSearch {...userSearchProps} /><UserList {...userListProps} /><UserModal {...userModalProps} /></div>);
}// 指定订阅数据,这里关联了 users
function mapStateToProps({ users }) {return { users };
}// 建立数据关联关系
export default connect(mapStateToProps)(Users);

展示容器——接收指令,开工

一般来说,展示容器推荐使用 无状态函数 的方式生成

一个良好的展示容器应该是彼此独立的,这也是一个良好的分工社会应该具备的,大家各司其职,因此这里通常使用无状态函数生成一个组件。在这里,通常是根据props传入的值去处理相应的事情(老板要你干嘛就干嘛)。

// 从props里获取指令(数据)const UserList = ({total,current,loading,dataSource,
}) => {const columns = [……];// 开始工作,构建组件的渲染return (  <div><Tablecolumns={columns}dataSource={dataSource}loading={loading}/></div>);
}

这样看下来,这种社会分工好像运行的挺顺畅的。那这就是这个社会的全貌吗?当然不是,实际的生活中,组件的区分可以更加精确更加精细。

例如有一些组件设计模式里把组件模式细分为:

  • Proxy component

  • Presentational component

  • Layout component

  • Container component

  • Higher-order component (HOC's)

  • Render callback

但是,我个人认为以上两种划分已经足够应付生活中的绝大部分情形,剩下的,可以通过两者的组合实现mixed Component

总结

这样看下来,这种社会分工好像运行的挺顺畅的,实际上,这种分类方式也是 很多开发者经验的总结。

根据“约定优于配置(convention over configuration)”的思想,提前做一定的规范肯定是没错的,但很多人将这种分工看做了他们设计组件的教条,这样就不好了,因为凡事总有例外,也许在某些复杂的业务场景中,Container 和 Components需要混用。你需要灵活的去使用,这也是为什么Dan修改了自己文章:

I amended the article because people were taking the separation as a dogma. 90% of React users don’t ever plan to have something like a living styleguide. There is no need to make life harder for them. Even those that do, don’t need to make every component available in such tool.

适合自己的才是最好的。

何苦让生活更艰难?

最后,再说说比较好的应用开发步骤是什么?我觉得可能是:

  1. 彻底弄清楚你要做什么

  2. 功能的划分

  3. 根据功能组织目录结构

  4. 设计你的数据模型(modal)

  5. 设计你的容器,确定整体框架结构

  6. 开始依次填充展示容器

  7. 连接组件和数据模型

  8. 测试

参考

Composite pattern

React component patterns

React Patterns

Presentational and Container Components

Container Components

React.js Conf 2015 - Making your app fast with high-performance components

Components and Props

Guide to Using the Composite Pattern with JavaScript

dva快速上手

免费体验云安全(易盾)内容安全、验证码等服务

更多网易技术、产品、运营经验分享请点击。

相关文章:
【推荐】 在Android中使用Protocol Buffers(中篇)

转载于:https://www.cnblogs.com/zyfd/p/9882021.html

用上帝视角来看待组件的设计模式相关推荐

  1. React组件常用设计模式之Render Props

    自己在总结最近半年的React开发最佳实践时,提到了Render Props,想好好写写,但感觉篇幅又太长,所以就有了此文.愿你看完,能有所收获,如果有什么不足或错误之处还请指正.文中所提到的所有代码 ...

  2. Everyday-FE-Articles 8~11月前端文章日推 [持续更新]

    Everyday-FE-Articles 由来自@阿里马跃的每日文章推荐,于是顺手整理,以便学习... -- By Ale-cc /* 注:序号不准确 */ 八月份 8月7日 星期二,农历六月廿六 S ...

  3. pyqt 获取 UI 中组件_你想知道的React组件设计模式这里都有(上)

    本文梳理了容器与展示组件.高阶组件.render props这三类React组件设计模式 往期回顾:HBaseCon Asia 2019 Track 3 概要回顾 随着 React 的发展,各种组件设 ...

  4. 《大话设计模式》第29章-OOTV杯超级模式大赛—模式总结(四)

    <大话设计模式>将于11月底由清华大学出版社出版 <大话设计模式>第29章-OOTV杯超级模式大赛-模式总结(一) <大话设计模式>第29章-OOTV杯超级模式大赛 ...

  5. 【组件化开发】前端进阶篇之如何编写可维护可升级的代码

    前言 我还在携程的做业务的时候,每个看似简单的移动页面背后往往会隐藏5个以上的数据请求,其中最过复杂的当属机票与酒店的订单填写业务代码 这里先看看比较"简单"的机票代码: 然后看看 ...

  6. python设计模式之猴子补丁模式

    1.所有书中都没有把猴子补丁作为一种设计模式来看待.因为设计模式的模式的命名是根据java中提炼出来的,语言方式决定了java绝对不会有也不需要有这种操作,不存在的.那自然设计模式不会包括猴子补丁模式 ...

  7. 《大话设计模式》第29章-OOTV杯超级模式大赛—模式总结(五)

    <大话设计模式>将于11月底由清华大学出版社出版 <大话设计模式>第29章-OOTV杯超级模式大赛-模式总结(一) <大话设计模式>第29章-OOTV杯超级模式大赛 ...

  8. 一文详解 React 组件类型

    本文的目标是让开发者清晰地了解 React 组件类型,哪些在现代 React 应用中依然在使用,以及为何一些类型现在不再使用了. 作者 | Robin Wieruch 译者 | 弯月 责编 | 屠敏 ...

  9. 设计模式的1000+篇文章总结

    设计模式的1000+篇文章总结 本文收集和总结了有关设计模式的1000+篇文章,由于篇幅有限只能总结近期的内容,想了解更多内容可以访问:https://www.ai2news.com/, 其分享了有关 ...

  10. 李建忠老师-设计模式

    前言(1) 课程目标理解松耦合设计思想掌握面向对象设计原则掌握重构技法改善设计掌握GOF核心设计补充:GOF(Gong of Gour)就是四人帮的全称.下面这本书的作者.Design Pattern ...

最新文章

  1. Java中 this关键字详解
  2. php 数学函数bc的使用(浮点数计算)
  3. Java中空值处理的感受
  4. mysql locking_Mysql next-key locking,读锁,写锁
  5. Sharepoint 2013设置customErrors
  6. PHP版_游戏扫码登录器程序源码
  7. 网络驱动器映射成功但无法实时更新文件需要重新连接_无边界办公——WebDAV文件共享服务构建...
  8. python判断线程结束_判断Threading.start新线程是否执行完毕的实例
  9. 如何在苹果Mac上快速将表情符号添加到电子邮件?
  10. 0x3a能否作为c语言常量,C语言编程遇到了宏定义的问题,求解答,万分感谢
  11. Microsoft SQL Server 2005简体中文开发版下载说明
  12. tf卡可以自己裁剪成nm卡_[Vivado 2020.1]ZYNQ7020折腾之路(四)之荔枝糖Hex固化程序到TF卡...
  13. Navicat Premium for Mac 11.1.8 免费中文破解版下载
  14. 阿里云mysql读写分离实现_MySQL-Proxy实现MySQL读写分离
  15. KK课表抓取教务系统
  16. ZigBee入门之基础概念3
  17. pandas 根据筛选条件对指定excel列进行筛选
  18. 计算机英语情景对话二人组,英语情景对话要求两人的对话 时间5分钟左右 内容是在校园两个好朋友谈论...
  19. oracle 字符串分割成数组_oracle 中如何分割字符串成为数组?
  20. 页面局部刷新( ScriptManager 和 UpdatePanel)(转)

热门文章

  1. c语言有结构体的200行代码,C语言——结构体(示例代码)
  2. python生成矢量图_Jupyter Notebook输出矢量图实例
  3. class type
  4. Mybatis的注解应用之关系映射
  5. MyBatis基于Java API配置
  6. 协方差 方差 以及线性相关理解
  7. 大型网站技术架构读书笔记
  8. [转] crontab命令
  9. Java Map在遍历过程中删除元素
  10. sublime设置代码缩进