文:徐超,《React进阶之路》作者

授权发布,转载请注明作者及出处


React 深入系列2:组件分类

React 深入系列,深入讲解了React中的重点概念、特性和模式等,旨在帮助大家加深对React的理解,以及在项目中更加灵活地使用React。

React 组件有很多种分类方式,常见的分类方式有函数组件和类组件,无状态组件和有状态组件,展示型组件和容器型组件。好吧,这又是一篇咬文嚼字的文章。但是,真正把这几组概念咬清楚、嚼明白后,对于页面的组件划分、组件之间的解耦是大有裨益的。

函数组件和类组件

函数组件(Functional Component )和类组件(Class Component),划分依据是根据组件的定义方式。函数组件使用函数定义组件,类组件使用ES6 class定义组件。下面是函数组件和类组件的简单示例:

  1. // 函数组件
  2. function Welcome(props) {
  3. return <h1>Hello, {props.name}</h1>;
  4. }
  5. // 类组件
  6. class Welcome extends React.Component {
  7. render() {
  8. return <h1>Hello, {this.props.name}</h1>;
  9. }
  10. }

上面的两种写法是等价的,但函数组件的写法要比类组件简洁,不过类组件比函数组件功能更加强大。类组件可以维护自身的状态变量,即组件的state,类组件还有不同的生命周期方法,可以让开发者能够在组件的不同阶段(挂载、更新、卸载),对组件做更多的控制。

类组件有这么多优点,是不是我们在开发中应该首选使用类组件呢?其实不然。函数组件更加专注和单一,承担的职责也更加清晰,它只是一个返回React 元素的函数,只关注对应UI的展现。函数组件接收外部传入的props,返回对应UI的DOM描述,仅此而已。当然,如上面例子所示,使用只包含一个render方法的类组件,可以实现和函数组件相同的效果。但函数组件的使用可以从思想上迫使你在设计组件时多做思考,更加关注逻辑和显示的分离,设计出更加合理的页面上组件树的结构。实际操作上,当一个组件不需要管理自身状态时,可以把它设计成函数组件,当你有足够的理由发现它需要“升级”为类组件时,再把它改造为类组件。因为函数组件“升级”为类组件是有一定成本的,这样就会要求你做这个改造前更认真地思考其合理性,而不是仅仅为了一时的方便就使用类组件。

无状态组件和有状态组件

无状态组件(Stateless Component )和有状态组件(Stateful Component),划分依据是根据组件内部是否维护state。无状态组件内部不使用state,只根据外部组件传入的props返回待渲染的React 元素。有状态组件内部使用state,维护自身状态的变化,有状态组件根据外部组件传入的props和自身的state,共同决定最终返回的React 元素。

很容易知道,函数组件一定是无状态组件,类组件则既可以充当无状态组件,也可以充当有状态组件。但如上文所述,当一个组件不需要管理自身状态时,也就是无状态组件,应该优先设计为函数组件。

展示型组件和容器型组件

展示型组件(Presentational Component)和容器型组件(Container Component),划分依据是根据组件的职责。

展示型组件的职责是:组件UI长成什么样。展示型组件不关心组件使用的数据是如何获取的,以及组件数据应该如何修改,它只需要知道有了这些数据后,组件UI是什么样子的即可。外部组件通过props传递给展示型组件所需的数据和修改这些数据的回调函数,展示型组件只是它们的使用者。展示型组件一般是无状态组件,不需要state,因为展示型组件不需要管理数据,但当展示型组件需要管理自身的UI状态时,例如控制组件内部弹框的显示与隐藏,是可以使用state的,这时的state属于UI state。既然大部分情况下展示型组件不需要state,应该优先考虑使用函数组件实现展示型组件。

容器型组件的职责是:组件数据如何工作。容器型组件需要知道如何获取子组件所需数据,以及这些数据的处理逻辑,并把数据和逻辑通过props提供给子组件使用。容器型组件一般是有状态组件,因为它们需要管理页面所需数据。

例如,下面的例子中,UserListContainer是一个容器型组件,它获取用户列表数据,然后把用户列表数据传递给展示型组件UserList,由UserList负责UI的展现。

  1. class UserListContainer extends React.Component{
  2. constructor(props){
  3. super(props);
  4. this.state = {
  5. users: []
  6. }
  7. }
  8. componentDidMount() {
  9. var that = this;
  10. fetch('/path/to/user-api').then(function(response) {
  11. response.json().then(function(data) {
  12. that.setState({users: data})
  13. });
  14. });
  15. }
  16. render() {
  17. return (
  18. <UserList users={this.state.users} />
  19. )
  20. }
  21. }
  22. function UserList(props) {
  23. return (
  24. <div>
  25. <ul className="user-list">
  26. {props.users.map(function(user) {
  27. return (
  28. <li key={user.id}>
  29. <span>{user.name}</span>
  30. </li>
  31. );
  32. })}
  33. </ul>
  34. </div>
  35. )
  36. }

展示型组件和容器型组件是可以互相嵌套的,展示型组件的子组件既可以包含展示型组件,也可以包含容器型组件,容器型组件也是如此。例如,当一个容器型组件承担的数据管理工作过于复杂时,可以在它的子组件中定义新的容器型组件,由新组件分担数据的管理。展示型组件和容器型组件的划分完全取决于组件所做的事情。

总结

通过上面的介绍,可以发现这三组概念有很多重叠部分。这三组概念都体现了关注点分离的思想:UI展现和数据逻辑的分离。函数组件、无状态组件和展示型组件主要关注UI展现,类组件、有状态组件和容器型组件主要关注数据逻辑。但由于它们的划分依据不同,它们并非完全等价的概念。它们之间的关联关系可以归纳为:函数组件一定是无状态组件,展示型组件一般是无状态组件;类组件既可以是有状态组件,又可以是无状态组件,容器型组件一般是有状态组件。

下篇预告:

React 深入系列3:State 和 Props


新书推荐《React进阶之路》

作者:徐超

毕业于浙江大学,硕士,资深前端工程师,长期就职于能源物联网公司远景智能。8年软件开发经验,熟悉大前端技术,拥有丰富的Web前端和移动端开发经验,尤其对React技术栈和移动Hybrid开发技术有深入的理解和实践经验。



美团点评广告平台大前端团队招收2019\2020年前端实习生

有意者邮件:yao.zhou@meituan.com

React 深入系列2:组件分类的更多相关文章

  1. React Native 系列(五) -- 组件间传值

    前言 本系列是基于React Native版本号0.44.3写的.任何一款 App 都有界面之间数据传递的这个步骤的,那么在RN中,组件间是怎么传值的呢?这篇文章将介绍到顺传.逆传已经通过通知传值. ...

  2. React 深入系列1:React 中的元素、组件、实例和节点

    文:徐超,<React进阶之路>作者 授权发布,转载请注明作者及出处 React 深入系列,深入讲解了React中的重点概念.特性和模式等,旨在帮助大家加深对React的理解,以及在项目中 ...

  3. React 深入系列4:组件的生命周期

    文:徐超,<React进阶之路>作者 授权发布,转载请注明作者及出处 React 深入系列4:组件的生命周期 React 深入系列,深入讲解了React中的重点概念.特性和模式等,旨在帮助 ...

  4. 关于React采坑(憨批)系列---类组件(class MyCom extends React.Component--VM47:9 Uncaught TypeError: Super expression must either be null or a function, not undefined)

    今天在学习React中的类组件时,突然给我报错VM47:9 Uncaught TypeError: Super expression must either be null or a function ...

  5. react实战系列 —— react 的第一个组件

    react 的第一个组件 写了 react 有一个半月,现在又有半个月没写了,感觉对其仍旧比较陌生. 本文分两部分,首先聊一下 react 的相关概念,然后不使用任何语法糖(包括 jsx)或可能隐藏底 ...

  6. React学习系列

    React学习系列 系列学习react 翻译地址 https://scotch.io/tutorials/learning-react-getting-started-and-concepts 我是初 ...

  7. React文档翻译系列(二)Hello World

    这是React文档翻译系列的第二篇,前一篇介绍了如何安装react,本篇主要介绍react的知识体系,掌握了基本的知识体系,才能更好的学习React. Hello World 开始React最简单的方 ...

  8. React Native 系列(六) -- PropTypes

    前言 本系列是基于React Native版本号0.44.3写的.在我们之前的通过props实现组件间传值的时候,大家有没有发现在父组件传递值过去,在子控件获取props的时候没有提示,那么如何能实现 ...

  9. React 深入系列3:Props 和 State

    文:徐超,<React进阶之路>作者 授权发布,转载请注明作者及出处 React 深入系列3:Props 和 State React 深入系列,深入讲解了React中的重点概念.特性和模式 ...

随机推荐

  1. 区分replace()和replaceAll()

    replace():returns a string replacing all the old char or CharSequence to new char or CharSequence. r ...

  2. IDEA的配置

    一.使用配置 转自:http://blog.csdn.net/qq_27093465/article/details/52918873 setting: 设置外观和字体: 设置编辑器快捷键:   自动 ...

  3. conda创建py27虚拟环境安装theano(anaconda3)

    现在python3已经成为主流的python环境,大部分的package都兼容python3,仍然有一小部分,或者说是某一领域的package需要使用python2.本人现在主要在利用python做机 ...

  4. Linux系统-解压缩命令集合

    Linux系统-解压缩命令集合 linux zip命令 zip -r myfile.zip ./* 将当前目录下的所有文件和文件夹全部压缩成myfile.zip文件,-r表示递归压缩子目录下所有文件. ...

  5. KMP(构建next数组)

    字符串匹配算法KMP, 核心思想是尽可能利用已经匹配的结果, 跳过尽可能多的不需要匹配的情况 重点和难点都在next数组的建立上 1. KMP算法的next数组求解 以模式串 a b a c a b ...

  6. 开篇/javascript基础知识点

    html css js 分别是一个网站的:内容  样式 行为: js 的三种样式:行内 内嵌 外链. 函数的特性:1.可以重复执行的代码块.2.不调用不执行.3.要访问里面,必须先执行. 内置对象:j ...

  7. Sublime 、NotePad++中查找匹配中文字符

    在Sublime .NotePad++中可以使用正则表达式 [\x{4e00}-\x{9fa5}] 查找匹配中文字符.

  8. C语言第三次博客作业

    一.PTA实验作业 1 1.实验代码 int i,N; char sex; float high; scanf("%d",&N); for(i =1;i <=N;i ...

  9. C语言函数2

    一.PTA实验作业 6-3 使用函数判断完全平方数: 1. 本题PTA提交列表: 2. 设计思路: 3.本题调试过程碰到问题及PTA提交列表情况说明: 1.一开始考虑让输入值N去整除一个循环变量i,i ...

  10. python实现线性回归

    参考:<机器学习实战>- Machine Learning in Action 一. 必备的包 一般而言,这几个包是比较常见的: • matplotlib,用于绘图 • numpy,数组处 ...