浅谈React中的元素、组件、实例和节点


Posted in Javascript onFebruary 27, 2018

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

React 中的元素、组件、实例和节点,是React中关系密切的4个概念,也是很容易让React 初学者迷惑的4个概念。现在,老干部就来详细地介绍这4个概念,以及它们之间的联系和区别,满足喜欢咬文嚼字、刨根问底的同学(老干部就是其中一员)的好奇心。

元素 (Element)

React 元素其实就是一个简单JavaScript对象,一个React 元素和界面上的一部分DOM对应,描述了这部分DOM的结构及渲染效果。一般我们通过JSX语法创建React 元素,例如:

const element = <h1 className='greeting'>Hello, world</h1>;

element是一个React 元素。在编译环节,JSX 语法会被编译成对React.createElement()的调用,从这个函数名上也可以看出,JSX语法返回的是一个React 元素。上面的例子编译后的结果为:

const element = React.createElement(
 'h1',
 {className: 'greeting'},
 'Hello, world!'
);

最终,element的值是类似下面的一个简单JavaScript对象:

const element = {
 type: 'h1',
 props: {
  className: 'greeting',
  children: 'Hello, world'
 }
}

React 元素可以分为两类:DOM类型的元素和组件类型的元素。DOM类型的元素使用像h1、div、p等DOM节点创建React 元素,前面的例子就是一个DOM类型的元素;组件类型的元素使用React 组件创建React 元素,例如:

const buttonElement = <Button color='red'>OK</Button>;

buttonElement就是一个组件类型的元素,它的值是:

const buttonElement = {
 type: 'Button',
 props: {
  color: 'red',
  children: 'OK'
 }
}

对于DOM类型的元素,因为和页面的DOM节点直接对应,所以React知道如何进行渲染。但是对于组件类型的元素,如buttonElement,React是无法直接知道应该把buttonElement渲染成哪种结构的页面DOM,这时就需要组件自身提供React能够识别的DOM节点信息,具体实现方式在介绍组件时会详细介绍。

有了React 元素,我们应该如何使用它呢?其实,绝大多数情况下,我们都不会直接使用React 元素,React 内部会自动根据React 元素,渲染出最终的页面DOM。更确切地说,React元素描述的是React虚拟DOM的结构,React会根据虚拟DOM渲染出页面的真实DOM。

组件 (Component)

React 组件,应该是大家最熟悉的React中的概念。React通过组件的思想,将界面拆分成一个个可以复用的模块,每一个模块就是一个React 组件。一个React 应用由若干组件组合而成,一个复杂组件也可以由若干简单组件组合而成。

React组件和React元素关系密切,React组件最核心的作用是返回React元素。这里你也许会有疑问:React元素不应该是由React.createElement() 返回的吗?但React.createElement()的调用本身也是需要有“人”负责的,React组件正是这个“责任人”。React组件负责调用React.createElement(),返回React元素,供React内部将其渲染成最终的页面DOM。

既然组件的核心作用是返回React元素,那么最简单的组件就是一个返回React元素的函数:

function Welcome(props) {
 return <h1>Hello, {props.name}</h1>;
}

Welcome是一个用函数定义的组件。如果使用类(class)定义组件,返回React元素的工作具体就由组件的render方法承担,例如:

class Welcome extends React.Component {
 render() {
  return <h1>Hello, {this.props.name}</h1>;
 }
}

其实,使用类定义的组件,render方法是唯一必需的方法,其他组件的生命周期方法都只不过是为render服务而已,都不是必需的。

现在来考虑下面这个例子:

class Home extends React.Component {
 render() {
  return (
   <div>
    <Welcome name='老干部' />
    <p>Anything you like</p>
   </div>
  )
 }
}

Home 组件使用了Welcome组件,返回的React元素为:

{
 type: 'div',
 props: {
  children: [
   {
    type: 'Welcome',
    props: {
     name: '老干部'
    }
   },
   {
    type: 'p',
    props: {
     children: 'Anything you like'
    }
   },
  ]
 }
}

对于这个结构,React 知道如何渲染type = 'div' 和 type = 'p' 的节点,但不知道如何渲染type='Welcome'的节点,当React 发现Welcome 是一个React 组件时(判断依据是Welcome首字母为大写),会根据Welcome组件返回的React 元素决定如何渲染Welcome节点。Welcome组件返回的React 元素为:

{
 type: 'h1',
 props: {
  children: 'Hello, 老干部'
 }
}

这个结构中只包含DOM节点,React是知道如何渲染的。如果这个结构中还包含其他组件节点,React 会重复上面的过程,继续解析对应组件返回的React 元素,直到返回的React 元素中只包含DOM节点为止。这样的递归过程,让React 获取到页面的完整DOM结构信息,渲染的工作自然就水到渠成了。

另外,如果仔细思考的话,可以发现,React 组件的复用,本质上是为了复用这个组件返回的React 元素,React 元素是React 应用的最基础组成单位。

实例 (Instance)

这里的实例特指React组件的实例。React 组件是一个函数或类,实际工作时,发挥作用的是React 组件的实例对象。只有组件实例化后,每一个组件实例才有了自己的props和state,才持有对它的DOM节点和子组件实例的引用。在传统的面向对象的开发方式中,实例化的工作是由开发者自己手动完成的,但在React中,组件的实例化工作是由React自动完成的,组件实例也是直接由React管理的。换句话说,开发者完全不必关心组件实例的创建、更新和销毁。

节点 (Node)

在使用PropTypes校验组件属性时,有这样一种类型:

MyComponent.propTypes = { 
 optionalNode: PropTypes.node,
}

PropTypes.node又是什么类型呢?这表明optionalNode是一个React 节点。React 节点是指可以被React渲染的数据类型,包括数字、字符串、React 元素,或者是一个包含这些类型数据的数组。例如:

// 数字类型的节点
function MyComponent(props) {
 return 1;
}

// 字符串类型的节点
function MyComponent(props) {
 return 'MyComponent';
}

// React元素类型的节点
function MyComponent(props) {
 return <div>React Element</div>;
}

// 数组类型的节点,数组的元素只能是其他合法的React节点
function MyComponent(props) {
 const element = <div>React Element</div>;
 const arr = [1, 'MyComponent', element];
 return arr;
}

// 错误,不是合法的React节点
function MyComponent(props) {
 const obj = { a : 1}
 return obj;
}

最后总结一下,React 元素和组件的概念最重要,也最容易混淆;React 组件实例的概念大家了解即可,几乎使用不到;React 节点有一定使用场景,但看过本文后应该也就不存在理解问题了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
判断是否输入完毕再激活提交按钮
Jun 26 Javascript
firefox下jQuery UI Autocomplete 1.8.*中文输入修正方法
Sep 19 Javascript
JS实现时间格式化的方式汇总
Oct 16 Javascript
AngularJS手动表单验证
Feb 01 Javascript
JavaScript数据存储 Cookie篇
Jul 02 Javascript
JS实现的JSON序列化操作简单示例
Jul 02 Javascript
详解使用VUE搭建后台管理系统(vue-cli更新至3.0)
Aug 22 Javascript
vue动态改变背景图片demo分享
Sep 13 Javascript
利用Electron简单撸一个Markdown编辑器的方法
Jun 10 Javascript
Vue 实现前进刷新后退不刷新的效果
Jun 14 Javascript
JS中async/await实现异步调用的方法
Aug 28 Javascript
JS 创建对象的模式实例小结
Apr 28 Javascript
AngularJS动态添加数据并删除的实例
Feb 27 #Javascript
JS严格模式知识点总结
Feb 27 #Javascript
总结js函数相关知识点
Feb 27 #Javascript
详解jQuery中的isPlainObject()使用方法
Feb 27 #jQuery
详解Vue Elememt-UI构建管理后台
Feb 27 #Javascript
详解react-native WebView 返回处理(非回调方法可解决)
Feb 27 #Javascript
Vue2.5通过json文件读取数据的方法
Feb 27 #Javascript
You might like
《PHP边学边教》(02.Apache+PHP环境配置――下篇)
2006/12/13 PHP
thinkphp文件引用与分支结构用法实例
2014/11/26 PHP
php将文本文件转换csv输出的方法
2014/12/31 PHP
PHP实现的ID混淆算法类与用法示例
2018/08/10 PHP
javascript实现轮显新闻标题链接
2007/08/13 Javascript
详解javascript中原始数据类型Null和Undefined
2015/12/17 Javascript
JavaScript函数内部属性和函数方法实例详解
2016/03/17 Javascript
新手学习前端之js模仿淘宝主页网站
2016/10/31 Javascript
使用JS批量选中功能实现更改数据库中的status状态值(批量展示)
2016/11/22 Javascript
swiper自定义分页器使用方法详解
2020/09/14 Javascript
js删除数组中的元素delete和splice的区别详解
2018/02/03 Javascript
jQuery实现ajax回调函数带入参数的方法示例
2018/06/26 jQuery
jQuery实现的3D版图片轮播示例【滑动轮播】
2019/01/18 jQuery
express框架中使用jwt实现验证的方法
2019/08/25 Javascript
详解element-ui级联菜单(城市三级联动菜单)和回显问题
2019/10/02 Javascript
nodejs各种姿势断点调试的方法
2020/06/18 NodeJs
基于vue实现微博三方登录流程解析
2020/11/04 Javascript
Python3.5字符串常用操作实例详解
2019/05/01 Python
Python深拷贝与浅拷贝用法实例分析
2019/05/05 Python
Python中的asyncio代码详解
2019/06/10 Python
python数据库操作mysql:pymysql、sqlalchemy常见用法详解
2020/03/30 Python
CSS3属性 line-clamp控制文本行数的使用
2020/03/19 HTML / CSS
美国新蛋IT数码商城:Newegg.com
2016/07/21 全球购物
美国眼镜在线零售商:Dualens
2019/12/07 全球购物
临床医学应届生求职信
2013/11/06 职场文书
交通安全演讲稿
2014/01/07 职场文书
服装设计专业毕业生求职信
2014/04/09 职场文书
危爆物品安全大检查大整治工作方案
2014/05/03 职场文书
信电学院毕业生自荐书
2014/05/24 职场文书
主题党日活动总结
2014/07/08 职场文书
2014年四风问题个人对照自查剖析材料
2014/09/15 职场文书
2019新学期家长会工作计划
2019/08/21 职场文书
营销策划分析:怎么策划才能更好销量产品?
2019/09/04 职场文书
mysql中数据库覆盖导入的几种方式总结
2022/03/25 MySQL
Dubbo+zookeeper搭配分布式服务的过程详解
2022/04/03 Java/Android
PostgreSQL数据库去除重复数据和运算符的基本查询操作
2022/04/12 PostgreSQL