浅谈React中的元素、组件、实例和节点
React深入系列,深入讲解了React中的重点概念、特性和模式等,旨在帮助大家加深对React的理解,以及在项目中更加灵活地使用React。
React中的元素、组件、实例和节点,是React中关系密切的4个概念,也是很容易让React初学者迷惑的4个概念。现在,老干部就来详细地介绍这4个概念,以及它们之间的联系和区别,满足喜欢咬文嚼字、刨根问底的同学(老干部就是其中一员)的好奇心。
元素(Element)
React元素其实就是一个简单JavaScript对象,一个React元素和界面上的一部分DOM对应,描述了这部分DOM的结构及渲染效果。一般我们通过JSX语法创建React元素,例如:
constelement=Hello,world;
element是一个React元素。在编译环节,JSX语法会被编译成对React.createElement()的调用,从这个函数名上也可以看出,JSX语法返回的是一个React元素。上面的例子编译后的结果为:
constelement=React.createElement(
'h1',
{className:'greeting'},
'Hello,world!'
);
最终,element的值是类似下面的一个简单JavaScript对象:
constelement={
type:'h1',
props:{
className:'greeting',
children:'Hello,world'
}
}
React元素可以分为两类:DOM类型的元素和组件类型的元素。DOM类型的元素使用像h1、div、p等DOM节点创建React元素,前面的例子就是一个DOM类型的元素;组件类型的元素使用React组件创建React元素,例如:
constbuttonElement=OK;
buttonElement就是一个组件类型的元素,它的值是:
constbuttonElement={
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元素的函数:
functionWelcome(props){
returnHello,{props.name}
;
}
Welcome是一个用函数定义的组件。如果使用类(class)定义组件,返回React元素的工作具体就由组件的render方法承担,例如:
classWelcomeextendsReact.Component{
render(){
returnHello,{this.props.name}
;
}
}
其实,使用类定义的组件,render方法是唯一必需的方法,其他组件的生命周期方法都只不过是为render服务而已,都不是必需的。
现在来考虑下面这个例子:
classHomeextendsReact.Component{
render(){
return(
Anythingyoulike
)
}
}
Home组件使用了Welcome组件,返回的React元素为:
{
type:'div',
props:{
children:[
{
type:'Welcome',
props:{
name:'老干部'
}
},
{
type:'p',
props:{
children:'Anythingyoulike'
}
},
]
}
}
对于这个结构,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元素,或者是一个包含这些类型数据的数组。例如:
//数字类型的节点
functionMyComponent(props){
return1;
}
//字符串类型的节点
functionMyComponent(props){
return'MyComponent';
}
//React元素类型的节点
functionMyComponent(props){
returnReactElement;
}
//数组类型的节点,数组的元素只能是其他合法的React节点
functionMyComponent(props){
constelement=ReactElement;
constarr=[1,'MyComponent',element];
returnarr;
}
//错误,不是合法的React节点
functionMyComponent(props){
constobj={a:1}
returnobj;
}
最后总结一下,React元素和组件的概念最重要,也最容易混淆;React组件实例的概念大家了解即可,几乎使用不到;React节点有一定使用场景,但看过本文后应该也就不存在理解问题了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。