React 是一个构建视图层的类库。不管React本身如何复杂,不管其他生态多么庞大,构建视图始终是他的核心。 React Element 简单的说,React Element 描述了“你想”在屏幕上看到的事物。 抽象的说,React Element 元素是一个描述了Dom Node的对象。 因为 React Element并不是你在屏幕上看见的真实事物。相反的它是一个描述真实事物的集合。
Javascript 对象很轻量。用对象来作为 React Element,那么React可以轻松的创建或销毁这些元素,而不必去太担心操作成本;React 具有分析这些对象的能力,也就是具有分析虚拟Dom的能力。当改变出现的时候,(相比于真实Dom)更新虚拟Dom的性能优势非常明显。 我们创建React Element的方法。 const element = React.createElement( 'div', {id:'login-btn'}, 'login' )这里 Reac.createElement方法接收三个参数:
表示标签名的字符串(div,span,etc);当前 React Element 需要具有的属性;当前 React Element要表达的内容,或者一个子元素。 上面调用React.createElement 方法之后会返回一个 javascript 对象: { type:'div', props:{ children:'Login', id:'login-btn' } }接着当我们使用ReactDOM.render方法,这才渲染到真实的DOM上,就会得到:
<div id='login-btn'>Login</div>我们在真正开发的时候,并不是直接使用React。createElement,而是出现了React组件,React Component。 没错,组件就是一个函数或者一个Class (当然Class 也是 function),它根据输入参数,并最终返回一个 React Element,而不需要我们直接手写无聊的React Element。
所以说,实际上我们使用了 React Component 来生成 React Element。 当然并不是所有的React Component 都需要返回 React Element ,它们还可以实现一些巧妙的设计和思想
function Buttom({onLogin}){ return React.createElement( 'div', {id:'login-btn',onclick:onLogin}, 'Login' ) }定义了一个Button组件,它接收 onLogin 参数,并返回一个 React Element 。 注意 onLogin 参数是一个函数,并最终像id:‘login-btn’ 一样成为了这个 React Element的属性。 直到目前,我们见到了React Element type为HTML标签的情况,其实我们也可以传递另一个 React Element:
const element = React.createElement( User, {name:'Lucas'}, null )注意此时 React.createElement 第一个参数是拎一个 React Element ,这与type值为HTML标签的情况不相同,当 React 发现type值为一个 class 或者函数时,它就会先看这个class 换货函数会返回什么样的Element ,并为这个 Element 设置正确的属性。
React 会一直不断重复这个过程(类似于递归),知道没有createElement 调用 type 值为class 或者 function 的情况。
function Button ({addFriend}){ return React.createElement( 'button', {onClick:addFriend}, 'Add Friend' ) } function User({name,addFriend}) { return React.createElement( 'div', null, React.createElement('p',null,name), React.createElement(Button,{addFriend}) ) }上面有两个组件:Button 和 User , User描述的Dom是一个div标签,这个div内,又存在一个p标签,这个 p 标签展示了用户的name;还存在一个Button。 那么React.createElement的返回情况:
function Button({ addFriend }){ return { type:'button', props:{ onClick:addFriend, children:'Add Friend' }, } } function User({name,addFriend}){ return { type:'div', props:{ children:[{ type:'p', props:{children:name} },{ type:Button, props:{ addFriend } }] } } }你会发现,上面的输出中,我们发现了四种type值: button,div,p,Button
当React 发现 type 是 Button时,它会查询这个Button组件会返回什么样的 React Element,并赋予正确的 props。 直到最终,React 会得到完整的表述 Dom 树的对象。在我们的例子中,就是:
{ type:'div', props:{ children:[{ type:'p', props:{children:'Tyler McGinnis'} },{ type:'button', props:{ onClick:addFriend, children:'Add Friend' } }] } }React 处理这些逻辑的过程就属于 reconciliation 的一部分,当然完整的 reconciliation更加复杂,涉及到的层面包括diff,render等,(Component到vdom,对vdom做diff,并更新到dom) 那么这个过程(reconciliation)什么时候触发呢,每次 setState 或 ReactDOM.render调用时。
我们在 React Component 编写时,相信大家都在使用 JSX 来描述 Dom。当然也可以脱离 JSX 二存在,毕竟JSX是一个语法糖,不吃当然也可以。 Babel为我们做了JSX到React.createElement这件事,做了一层编译。