jsx语法
首先介绍jsx语法 , 其实jsx= javascript + xml,看上去是html其实不是.
let element = <h1 id='myid'>hello world</h1>
通过bable 转义后变成
let element= React.createElement('h1',{id:'myid'},'hello world')
//这里我们称React元素,这是React最小单位
render渲染
写完React元素,就可以render渲染,就可以在页面中呈现了.
ReactDom.render(element,document.getELementById('root'))
那么我们按照源码开始再手写一下render和createElement
createElement
- createElement函数的目标是把传进来的(‘h1′,{id:’myid’},’hello world’)参数变成一个React元素
如图这个就是我们要的react元素
function createElement(type,config={},children){
let props={};
for(let propsName in config){
props[propsName]=config[propsName]
};
let childrenLength = arguments.length-2;
if(childrenLength==1){
props.children=children
}else if( childrenLength >1){
props.children=Array.from(arguments).slice(2)
}
let element={type,props}
return element
}
思路:
- 三个参数,参数1是我们的type可直接返回,参数2和参数3我们需要把它们塞进一个props对象里面
- 首先创建一个props空对象,遍历config,依次添加进props对象里
- 截取children长度,判断长度若是1说明是文本节点可直接添加,大于1则是一个数组,我们返回数组即可
render
render函数是把React元素(虚拟dom)渲染成html
function render(element,parentNode){
if(typeof element == 'string' || typeof element =='number'){
return parentNode.appendChild(document.createTextNode(element))
}
let {type,props}=element;
let domElement = document.createElement(type);
for(let propsName in props){
switch(propsName){
case propsName=='className':
return domElement.className=props[propsName];
case propsName=='style':
let styobj= props[propsName]
for(let attr in styobj){
domElement.style[attr]=styobj[attr]
}
return
case propsName=='children':
let children = Array.isArray(props.children)?props.children:[props.children]
children.forEach(element=>{
render(element,domElement)
})
return
default:
domElement.setAttribute(propsName,props[propsName])
}
}
parentNode.appendChild(domElement)
}
思路:
-
render函数2个参数分别为react元素,根组件,我们先判断react元素是不是string和number因为可以直接渲染比如像这样
ReactDom.render('abc',document.getElementById('root'))
- 当参数1 是个react元素的时间,我们就得去做判断,首先我们可以分别解构出type,props,然后我们用type创建出元素,遍历props让type元素依次添加属性.
- 需要考虑特性情况如className,style就得去分别去做处理在添加,其他的直接用setAttribute添加进去.
- 最后通过根元素把我们创建出来的appendChild添加进去.
当我们元素是函数组件的时候
function Welcome(props){
return React.createElement('h1',{id:'zhufeng'},props.name,props.age)
}
ReactDOM.render(element, document.getElementById('root'));
我们得在render里面去添加逻辑,只需要把这个函数执行后就可,因为它的返回值还是我们的react元素.
function render(element,parentNode){
if(typeof element == 'string' || typeof element =='number'){
return parentNode.appendChild(document.createTextNode(element))
}
let {type,props}=element
+ if(typeof type == 'function'){
+ let newElemet=type(props)
+ type=newElemet.type;
+ props=newElemet.props;
}
//以下逻辑相同
}
当我们元素是类组件的时候
class Welcome1 extends React.Components{
render(){
return React.createElement('h1',{id:'classwelcome'},this.props.name,this.props.age)
}
}
同样的思路,我们先去创建一个Components组件让它去继承.
class Components{
static isReactComponents=true
constructor(props){
this.props=props
}
}
这个组件我们只需要去传递props让子组件去继承就可以,另外isReactComponents这个静态属性是用来标识是否是类组件.
接下来我们继续改render函数
function render(element,parentNode){
if(typeof element == 'string' || typeof element =='number'){
return parentNode.appendChild(document.createTextNode(element))
}
let {type,props}=element
+ if(type.isReactComponents){
+ let newElemet=new type(props).render()
+ type=newElemet.type;
+ props=newElemet.props;
+ }else if(typeof type == 'function'){
+ let newElemet=type(props)
+ type=newElemet.type;
+ props=newElemet.props;
+ }
}
//以下逻辑相同
}
那么我们就可以顺利跑通啦.
原文地址:https://segmentfault.com/a/1190000021642243