JSX
JSX是一種JavaScript的語(yǔ)法擴(kuò)展,運(yùn)用于React架構(gòu)中,其格式比較像是模版語(yǔ)言,但事實(shí)上完全是在JavaScript內(nèi)部實(shí)現(xiàn)的。我們能在React中直接編寫JSX代碼,得益于babel的轉(zhuǎn)譯,比如:
<div className='box'>
<span>test</span>
<span>{test}</span>
</div>
轉(zhuǎn)譯后:
/*#__PURE__*/
React.createElement("div", {
className: "box"
}, /*#__PURE__*/React.createElement("span", null, "test"), /*#__PURE__*/React.createElement("span", null, test));
也就是說轉(zhuǎn)譯之后默認(rèn)會(huì)調(diào)用React.createElement()方法。這也側(cè)面說明了即使你再寫函數(shù)組件的時(shí)候沒有顯示地引用React,也必須先import React from 'react'
React.createElement()
這里精簡(jiǎn)了方法的實(shí)現(xiàn)原理,并作了相關(guān)注釋
const hasOwnProperty = Object.prototype.hasOwnProperty;
/*
*@param {*} type 元素類型,或是組件類名
*@param {*} config 元素屬性
*@param {*} children 子元素
*/
function createElement(type, config, children) {
let propName;
const props = {};
//循環(huán)遍歷config中的屬性,并添加為props的屬性
if (config != null) {
for (propName in config) {
if (
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
props[propName] = config[propName];
}
}
}
//這段代碼主要是為了將子元素作為一個(gè)數(shù)組,保存到props的children屬性中。
//雖然形參只有一個(gè)children,但實(shí)參可能有多個(gè),除了第一個(gè)是type和第二個(gè)是config,其他都是children,即實(shí)參列表的長(zhǎng)度減2就是children的個(gè)數(shù)
const childrenLength = arguments.length - 2;
if (childrenLength === 1) {
//如果只有一個(gè)children,直接賦值
props.children = children;
} else if (childrenLength > 1) {
//如果children大于一個(gè),就把所有children保存到數(shù)組中,賦值給props.children
const childArray = Array(childrenLength);
for (let i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
}
if (__DEV__) {
if (Object.freeze) {
Object.freeze(childArray);
}
}
props.children = childArray;
}
//這里主要針對(duì)type是class類名的情況
//JSX中以大寫字母開頭的組件會(huì)被認(rèn)為是自定義組件,以小寫字母開頭的會(huì)被認(rèn)為是標(biāo)簽。自定義組件可能會(huì)有defaultProps
if (type && type.defaultProps) {
const defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
//ReactElement可以認(rèn)為是包含了這些屬性的一個(gè)對(duì)象,類似這樣的結(jié)構(gòu)
/* {
type:'div',
props:{
className:'box',
children:{
type:'span',
props:{
children:'test'
}
}
}
} */
return ReactElement(
type,
props,
);
}
小結(jié):JSX轉(zhuǎn)譯之后其實(shí)是一個(gè)ReactElement對(duì)象,虛擬DOM其實(shí)就是這樣的一個(gè)JS對(duì)象。