React 是一个构建视图层的类库。不管React本身如何复杂,不管其他生态多么庞大,构建视图始终是他的核心。
React Element
简单的说,React Element 描述了“你想”在屏幕上看到的事物。
抽象的说,React Element 元素是一个描述了Dom Node的对象。
因为 React Element并不是你在屏幕上看见的真实事物。相反的它是一个描述真实事物的集合。
const element = React.createElement(
'div',
{id:'login-btn'},
'login'
)
这里 Reac.createElement方法接收三个参数:
{
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这件事,做了一层编译。