组件的公共方法
组件的公共方法都被定义在了ReactComponent.Mixin中,这些公共方法可以分成如下几类:
分类 |
方法名称 |
初始化方法 |
construct |
组件挂载 |
mountComponent mountComponentIntoNode _mountComponentIntoNode |
组件卸载 |
unmountComponent unmountComponentFromNode |
属性更新 |
setProps receiveProps |
容器相关 |
getDOMNode isOwnedBy |
表中列出的方法,存在于所有ReactComponent及其子类的实例中,接下来我们逐一看看这些方法。
construct
注意不是constructor,construct方法负责完成对ReactComponent的初始化工作,它接受两个参数initialProps和children,分别代表该组件的初始属性和子元素集合。
记录Owner
初始化时,首先会记录下当前实例的Owner信息。Owner信息存储在ReactCurrentOwner.current中,所谓的Owner,就是负责渲染当前组件的那个组件,有点绕口,举个例子。
var a = React.createClass({
render: function(){
return (<ComponentA>
<ComponentB />
<ComponentC></ComponentC>
</ComponentA>)
}
})
上述代码中,a就是ComponentA、ComponentB以及ComponentC的Owner。ComponentA等在执行construct方法时,首先会在props中增加一个key为'{owner}'的属性,其值为a。
初始状态
组件在初始化是,componentLifeCycle状态是UNMOUNTED。
子元素
当construct方法的实际传参为1个时,说明该组件不包含子元素。
当construct实际参数为2个时,先判断第2个参数的类型,若为null、字符串或者数字时,就会直接作为props.children的值;若第2个参数的类型为数组,只要数组中的每一个元素都不是null或者布尔值时,就将它直接付给props.children。
若第2个参数的数组中包含了null或者布尔值,或者实际传参数量超过2个时,这时会从第2个参数开始,将所有后续参数添加到一个数组中(标记为Target),如果参数的类型是数组,那么这个数组中的每一个元素都会被添加到Target中。
组件挂载
与组件挂载相关的函数包括mountComponent、mountComponentIntoNode和_mountComponentIntoNode。组件挂载的过程十分复杂,不同类型的组件,挂载行为也有不同,因此,React框架将挂载行为的公共代码抽出来,放在ReactComponent的Mixin中,同时,ReactCompositeComponent和ReactNativeComponent中也包含挂载的处理代码。
在ReactComponent中,主要负责处理组件挂载时的ref处理和ComponentLifeCycle更新(mountComponent函数),还包括挂载时的事务调度(mountComponentIntoNode函数)以及实际的HTML代码注入到特定DOM节点(_mountComponentIntoNode函数),先理解流程,实现细节以后再讨论
组件卸载
组件卸载的过程相较挂载更为简单一些,卸载时将ref移除,并更新了ComponentLifeCycle的状态,更新DOM时也没有引入事务机制。
属性更新
setProps方法内部也调用了replaceProps方法,而进行组件属性更新时,将启用事务进行管理。具体的更新过程将用专门的章节讲解。
容器相关
与容器相关的接口有两个,isOwnedBy和getDOMNode。isOwnedBy来判断当前组件是否属于给定实例,直接通过比较props中的'{owner}'属性是否全等于传入参数来确定,参见"记录Owner"。
getDOMNode用来返回当前组件实例对应的容器DOM节点,React会将组件的容器节点缓存在this._rootNode上。如果_rootNode不为空,那么直接返回_rootNode就是目标容器节点。
如果_rootNode为空,则此时需要进行查询。组件在挂载时(ReactComponent.mountComponent),会将目标容器的id存储在rootNodeID这个内部属性中,在getDOMNode时,直接调用doucment.getElementById(this._rootNodeID)进行查询,如果查到了,就将该节点存储在_rootNode上,以便后续直接返回。如果仍然没有查到,说明该组件是被其他组件包含并渲染,此时需要向上查询对应的容器节点,通过调用ReactMount.findReactRenderedDOMNodeSlow来完成。