react组件设计思想学习——设计理念基础及组件分类

当开始独立负责一个完整的前端项目时,更能意识到自己对于一个大型项目组织的设计能力的强弱。如何拆分组件,如何在最初开发时就能尽可能的保证项目的可维护性,组件的高复用性。这个系列学习的重心便是react项目中的组件化拆分思想。

本章优先学习组件化的几个基本概念。基本概念彻底理解了,后期开发时自然更加得心应手。并且将对react组件的几种分类概念进行学习,这对于以后开发中页面的组件划分、组件之间的解耦是大有裨益的。

单一职责原则

单一职责原则是面向对象基本原则之一。核心定义:一个类或者模块应该有且只有一个改变的原因。通俗的讲就是一个类只能拥有一个职责,只负责一个功能,只干一件事。

对于react开发,我们可以将组件看做模块。以组件来解释为什么要遵循单一原则:比如一个组件同时拥有A和B两个功能,当需要对A功能进行修改时,可能由于莫须有的原因导致B功能出现问题。所以这里就需要将组件分解为A和B两个组件。

从单一职责原则来看待组件化拆分,应该将组件限制在一个合适的粒度上。比如一个标签页组件、一个表单组件。粒度不是越小越好,粒度最小太极端,这样会导致小型组件太多,管理更为困难。这个粒度应该是最适合被复用的程度。

比如表单组件,在实际开发中会多次使用到表单提交功能。那么将表单输入功能封装为一个组件就是一个合适被复用的程度,这比每次需要开发表单都一个一个添加输入框/选择器更为方便。而这个表单组件也只管理一个表单输入这一个功能,符合单一职责原则。

如何把握好组件粒度也是需要经验的,如果不知道应该怎么拆分,前期最合适的方法就是DRY(Don't Repeat Yourself)原则。不要偷懒,多思考,多重构去消除重复代码。

总结一下单一原则拆分组件的好处:

  1. 每个组件的复杂性大大降低,每个组件都有清晰的功能定义,可读性高;
  2. 可复用性更高;
  3. 可维护性高,不会牵一发而动全身。

高内聚, 低耦合

一个优秀的组件必然是高内聚,低耦合的。

所谓高内聚,是指一个软件模块内各个元素彼此结合的紧密程度要高,即一个软件模块是由相关性很强的代码组成,只负责一项任务,也就是单一责任原则。

所谓低耦合,是指一个软件系统内不同模块之间的互连程度要低。不同模块之间的联系越紧密,其耦合性就越强,模块的独立性则越差,模块间耦合的高低取决于模块间接口的复杂性、调用的方式及传递的信息。

应用到前端组件上,高内聚也就意味着组件有着明确的边界,将精密关联的功能聚集在一个组件内实现一个功能。一个组件是一个自包含的单元,也是一个独立的单元,它包含了内部所需要的样式(css)、逻辑(JavaScript)、结构(html)、资源(img、video等)。当然这个独立也是相对的,一个组件会包含多个粒度更小的单元。比如表单组件,就会包含输入框、选择器、开关等组件。

低耦合在前端组件则更好理解,应用肯定是由多个组件构成的,但这多个功能之间的关联性应该越小越好。比如单项数据流、组件A不应该能够访问组件B的内部函数等。

组件拆分的一些技巧:

  1. DRY原则
  2. 如果组件内部存在较多条件控制流, 这通常意味着需要对组件进行抽取

组件的分类

React 的组件有很多种分类方式。真正把这几组概念完全理解后,对于页面的组件划分、组件之间的解耦是大有裨益的。

展示组件和容器组件

展示组件,在多数项目中它位于components文件夹内。顾名思义,它的主要作用是“展示功能”。简单来说,就是UI长什么样,数据怎样显示出来。比如Page、List、Table。对于展示组件来说,它不需要关心数据的变化、获取、回调,数据和回调函数通过prop从上层组件进行传递。由于不需要管理数据,因此它的state主要用于本身UI的控制。

对于展示组件的设计和开发而言,应该尽可能的保证其和业务的解耦,和业务的耦合程度越低,那么该组件的可复用性就越高。比如著名的antd,便是展示组件,它不关心数据来源。设计开发展示组件时,应该以第三方组件库的标准为目标去进行,设计好对外暴露的接口(prop)、考虑多种情况下的可复用性。

而容器组件便是业务功能的直接体现。在多数项目中,容器组件通常位于container文件夹内。它的主要作用便是获取数据(比如接口请求或是从redux的store中获取)、数据的逻辑处理,并组合多个展示组件和更小功能块的容器组件来构筑目的功能。

当然,容器组件和展示组件并不是前者包含后者关系,使用场景不同,包含关系也就不同。它们是可以互相嵌套的。

展示组件和容器组件的分类可以带来的好处:

  1. 关注点分离。通过用这种方式开发组件,可以更好的理解业务需求和UI功能
  2. 更好的复用性。可以在不同的数据源中使用相同的展示型组件(比如纯粹的Table),也可以把它们放进不同容器型组件中更进一步的进行复用(比如专用于展示服务器信息的Table)
  3. 这种方法“强迫”开发者去把用于布局的组件抽出来,例如Sidebar,Page,ContextMenu。然后通过子组件的方式引入而不是在各个容器型组件中复制粘贴已有的样式和布局。

展示组件和容器组件的再次学习我阅读了这篇文章

函数组件和类组件

函数组件和类组件通过组件的定义方式来划分,函数组件使用函数定义的方式,类组件则使用了ES6的class。

//函数组件的定义
renderHelloWorld(props) (
    <div>
      {props.text}
    </div>
  )
//类组件的定义

class HelloWorld extends React.Component {
  render() {
    return <div>{this.props.text}</div>;
  }
}

两者的主要作用都是返回一个react的节点,不同的在于前者写法更为简洁,后者的功能则更为强大。类组件可以维护自身的state,有自身的生命周期方法,通过生命周期方法开发者可以在组件的不同阶段控制组件的内容展示(如组件加载、拆卸、更新)。

事实上,只包含一个render方法的类组件可以实现和函数组件同样的效果,那么为什么还存在函数组件呢?首先明显的,函数组件的性能更好,其次:

函数组件的使用可以从思想上迫使你在设计组件时多做思考,更加关注逻辑和显示的分离,设计出更加合理的页面上组件树的结构。实际操作上,当一个组件不需要管理自身状态时,可以把它设计成函数组件,当你有足够的理由发现它需要“升级”为类组件时,再把它改造为类组件。因为函数组件“升级”为类组件是有一定成本的,这样就会要求你做这个改造前更认真地思考其合理性,而不是仅仅为了一时的方便就使用类组件。

—— React 深入系列2:组件分类

有状态组件和无状态组件

这个分类命名中,状态就是指的state。因此有状态组件和无状态组件就很好理解了。无状态组件内部不使用state,完全由外部的props来渲染内容。有状态组件则通过内部的state和外部的props共同决定渲染的内容。

那么可以意识到,函数组件一定是无状态组件,类组件可能是无状态组件,也可能是有状态组件。

纯组件和非纯组件

纯组件的“纯”来源于函数式编程。指的是对于一个函数而言,给定相同的输入,它总是返回相同的输出,过程没有副作用,没有额外的状态依赖。对应到 React 中,纯组件指的是 props(严格上说还有 state 和 context,它们也是组件的输入)没有变化,组件的输出就不会变动。

纯函数的实例:

function sum(a, b) {
    return a + b;
}
sum(5, 10)

非纯函数则指的是,即便一个函数的所有输入相同,但输出可能不同。比如依赖全局状态的函数:

let said = false;

function sayOnce(message) {
    if (said) {
        return null;
    }
    said = true;
    return message;
}

sayOnce('Hello World!'); // => 'Hello World!'
sayOnce('Hello World!'); // => null

为什么要使用纯函数?因为纯函数没有副作用且不依赖于全局状态。只要输入相同,输出一定相同。因此,纯函数的结果是可预测的,确定的,可以复用,并且易于测试。纯组件也是相同的道理:

function Message({ text }) {
    return <div className="message">{text}</div>;
}

<Message text="Hello World!" />
// => <div class="message">Hello World</div>

调用纯组件Message时,只要传入的props相同,那么渲染出来的元素也一定相同。

当然,所有组件都是纯组件是不现实的,功能需要用户输入、需要网络请求、需要本地存储、也需要全局状态。因此开发者需要做的就是将纯组件和非纯组件隔离,即组件的提纯。

比如一个需要请求并显示返回的服务器列表的组件,我们可以将显示服务器列表的组件提取出来(和展示组件类似),将请求操作放在非纯组件内,数据传递给展示服务器列表这个纯组件。

[前端经典题目分析] ['1', '2', '3'].map(parseInt) what & why ? 
下一篇:[前端经典题目分析] ['1', '2', '3'].map(parseInt) what & why ?


仅有一条评论


  1. zsodur
    zsodur

    请问作者是原创吗?能否转载?

     Reply

如果我的文章对你有帮助,或许可以打赏一下呀!

支付宝
微信
QQ