virtual DOM
真實(shí)頁面對(duì)應(yīng)一個(gè)DOM
樹彻舰。在傳統(tǒng)頁面的開發(fā)模式中伐割,每一次需要更新頁面的時(shí)候,都需要手動(dòng)操作DOM
來進(jìn)行更新淹遵。
DOM
的操作是十分昂貴的口猜,我們?cè)谇岸碎_發(fā)中,性能消耗最大的就是DOM
操作透揣,而且這部分的代碼會(huì)讓整體項(xiàng)目的代碼變得難以維護(hù)济炎。React
把真實(shí)的DOM
樹轉(zhuǎn)換為JavaScript
對(duì)象樹,也就是virtual DOM
辐真。
每一次數(shù)據(jù)更新后须尚,重新計(jì)算Virtual DOM
,并和上一次生成的Virtual DOM
進(jìn)行比對(duì)侍咱,對(duì)發(fā)生變化的部分進(jìn)行批量更新耐床。Rect
也提供直接的shouldComponentUpdate
聲明周期回調(diào),來減少數(shù)據(jù)變化后的不必要的Virtual DOM
對(duì)比的過程楔脯,用來保證性能撩轰。
JSX語法
JSX
和React
有什么關(guān)系?簡(jiǎn)單的來說,React
為了方便view
層組件化堪嫂,承載了構(gòu)建HTML
結(jié)構(gòu)化頁面的職責(zé)偎箫,React
通過創(chuàng)建于與跟新虛擬元素(virtual DOM
)來管理整個(gè)Virtual DOM
。
React
創(chuàng)建虛擬元素可以劃分為兩類皆串,DOM
元素(DOM element
)與組件元素(component element
),分別對(duì)應(yīng)原生的DOM
元素和自定義元素淹办,而JSX
與創(chuàng)建元素有很大的關(guān)系。
JSX
的官方定義是類XML
語法的ECMAScript
擴(kuò)展恶复。它完美的利用了JavaScript
自帶的語法和特性怜森,并且使用大家熟悉的HTML
語法來創(chuàng)建虛擬元素“担可以說副硅,JSX
基本語法被XML
囊括了,但是也有少許不同的地方翅萤。
XML基礎(chǔ)語法
使用類XML
語法的好處是標(biāo)簽可以任意嵌套想许,我們可以像HTML
一樣清晰看到DOM
樹結(jié)構(gòu)和其屬性,比如我們構(gòu)建一個(gè)List
組件断序。
const List = () =>{
<div>
<Title>This is Title</Title>
<ul>
<li>list item</li>
</ul>
</div>
}
寫List
的過程就像寫HTML
一樣,只不過它被包裹在JavaScript
的方法中糜烹,但是在這個(gè)過程中需要注意以下幾點(diǎn):
- 標(biāo)簽一定要閉合
- 定義標(biāo)簽的時(shí)候违诗,只允許被一個(gè)標(biāo)簽包裹。所以上面的寫法是錯(cuò)誤的疮蹦。
const List = () =>{
<div>
<Title>This is Title</Title>
<ul>
<li>list item</li>
</ul>
</div>
<div>
<Title>This is Title</Title>
<ul>
<li>list item</li>
</ul>
</div>
}
元素類型
我們都知道JSX
語法中的元素分為DOM
元素(DOM element
)與組件元素(component element
),JSX
對(duì)應(yīng)的規(guī)則是HTML
標(biāo)簽是否為小寫字母诸迟,其中小寫字母對(duì)應(yīng)DOM
元素,而逐漸元素自然對(duì)應(yīng)的是首字母大寫愕乎。
注釋
事實(shí)上JSX
還是JavaScript
阵苇,依然可以用簡(jiǎn)單的方法使用注釋,唯一需要注意的是感论,在一個(gè)組件的子元素位置使用注釋需要{}
進(jìn)行包裹绅项,實(shí)例代碼如下:
const App = (
<Nav>
{/*節(jié)點(diǎn)注釋*/}
<Person
/*多行
注釋*/
name = {window.isLoggedIn?window.name : ''}
/>
</Nav>
)
元素屬性
在JSX
中,不論是DOM
元素還是組件元素比肄,它們都是有屬性的快耿,不同的是,DOM
元素的屬性是標(biāo)準(zhǔn)規(guī)范屬性芳绩,但是有兩個(gè)例外--class
和for
掀亥,這是因?yàn)樵?code>JavaScript中這兩個(gè)單詞是關(guān)鍵詞,因此我們這么轉(zhuǎn)換妥色。
-
class
屬性修改為className
-
for
屬性改為htmlFor
而組件元素的屬性是完全自定義的搪花,也可以理解成組件需要的參數(shù),舉個(gè)栗子:
const Header = ({title,children})=>{
<h3 title = {title}>{children}</h3>
};
<Header title='hello world'>hello world</Header>
我們可以對(duì)屬性進(jìn)行展開展開,這個(gè)應(yīng)用場(chǎng)景主要是撮竿,當(dāng)我們知道組件的全部屬性的時(shí)候吮便,使用JSX
可以這么寫:
//方法一
const component = <Component name = {name} value = {value}/>;
//方法二
const component = <Component / >;
component.props.name = name;
component .props.value = value;
// 方法三:使用ES6特性來提高效率
const data = {name:'foo', value:'bar'};
const component = <Component name = {data.name} value = {data.value}/>;
//方法三可以使用ES6來進(jìn)行簡(jiǎn)寫
const data = {name:'foo', value:'bar'};
const component = < Component {...data} />;
javaScript屬性表達(dá)式
屬性值要使用表達(dá)式的話,只要使用{}
進(jìn)行替換即可倚聚。
//輸入(JSX)
const person = <Person name ={window.isLoggedIn ? window.name:''} />
//輸出(JavaScript)
const person = React.createElement (
person,
{name:window.isLoggedIn ? window.name:' '}
);
其中子組件也可以作為表達(dá)式使用:
//輸入(JSX)
const content = <Container>{window.idLoggedIn ? <Nav /> :<login />}</Container>
//輸出(JavaScript)
const content = React.createElement (
Container,
null,
{name:window.isLoggedIn ? React.createElement(Nav) : React.createElement(Login)}
);
小結(jié):
-
JSX
是一個(gè)看起來很像XML
的JavaScript
語法擴(kuò)展线衫,這種語法允許你在寫JavaScript
中寫可嵌套的閉合標(biāo)簽。 -
JSX
與HTML
語法很像惑折,可以嵌套授账,可以自定義屬性。 -
JSX
允許在閉合標(biāo)簽中使用JavaScript
表達(dá)式惨驶,但是要被{}
所包裹 -
JSX
中的內(nèi)聯(lián)樣式也是通過style
屬性來定義的白热,但屬性值不能是字符串而必須為對(duì)象,而且要注意對(duì)象中的屬性名需要使用駝峰命名法粗卜。 - 在
JSX
中屋确,標(biāo)簽子節(jié)點(diǎn)內(nèi)的注釋應(yīng)該寫在{}
內(nèi)。 -
JSX
中的數(shù)組會(huì)自動(dòng)的展開所有的成員续扔,但是需要注意的是攻臀,如果數(shù)組或是迭代器中的每一項(xiàng)都是HTML
標(biāo)簽或是組件的話,那么他們必須要擁有唯一的key
屬性
React組件
其實(shí)對(duì)組件的封裝很類似與面向?qū)ο蟮乃枷肷疵粒换セ旧弦圆僮?code>DOM為主刨啸,邏輯上是結(jié)構(gòu)上哪里需要變,我們就操作哪里识脆。此外设联,對(duì)于JavaScript
的結(jié)構(gòu),我們得到了幾項(xiàng)規(guī)范標(biāo)準(zhǔn)組件的信息灼捂。
- 基本的封裝性:盡管說
JavaScript
沒有真正的面向?qū)ο蟮姆椒ɡ肜俏覀冞€是可以通過實(shí)例化的方法來制造對(duì)象。 - 簡(jiǎn)單的生命周期:最明顯的兩個(gè)方法是:
constructor
和destroy
悉稠,代表了組件的掛載卸載的過程宫蛆,但是除此之外,其他過程(如更新時(shí)的聲明周期)并沒有體現(xiàn)偎球。 - 明確的數(shù)據(jù)流動(dòng):這里的數(shù)據(jù)指的是地道用組件的參數(shù)洒扎。一旦確定參數(shù)的值,就會(huì)解析傳進(jìn)來的參數(shù)衰絮,根據(jù)參數(shù)的不同做出不同的響應(yīng)袍冷,從而得到渲染的結(jié)果。
Web Components
規(guī)范:這個(gè)規(guī)范想要同意web
端關(guān)于組件的定義猫牡,它可以通過定義Custom Elements
(自定義元素)的方式來統(tǒng)一組件胡诗。每一個(gè)自定義元素可以定義自己對(duì)外提供的屬性、方法、還有事件煌恢,內(nèi)部可以像寫一個(gè)頁面一樣骇陈,專注于實(shí)現(xiàn)功能來完成對(duì)組件的封裝。
Web Components
定義了一切我們想要的組件化的概念瑰抵,其中HTML Template
定義了之前的模板概念你雌,Customer Element
定義了組件的展現(xiàn)形式,shadow DOM
定義了組件的作用域范圍二汛,可以包括樣式婿崭,HTML Imports
提出了新的引入方式。
React組件的構(gòu)建
React
組件即為組件元素:組件元素描述成純粹的Json
對(duì)象肴颊,意味著可以使用方法或是類來構(gòu)建氓栈。React
組件即為組件元素,組件基本上由3個(gè)部分組成-- 屬性(props
)婿着、狀態(tài)(state
)以及生命周期方法授瘦,這里我們從一張圖來簡(jiǎn)單的概括React
。
React
組件可以接受參數(shù)竟宋,也可以有自身的狀態(tài)提完,一旦接受到的參數(shù)或是自身的狀態(tài)有所改變,React
組件就會(huì)執(zhí)行相對(duì)應(yīng)的生命周期的方法丘侠,最后渲染氯葬,整個(gè)過程完全符合傳統(tǒng)組件所定義的組件職責(zé)。
React和web component的關(guān)系
React
和web component
傳達(dá)的理念是一致的婉陷,但是二者的實(shí)現(xiàn)方式是不同的,
-
React
自定義元素的庫(kù)是自己構(gòu)建的官研,與web component
規(guī)范是不一致的 -
React
渲染過程包含了模板的概念秽澳,也就是之前說的JSX
-
React
組件的實(shí)現(xiàn)均在方法和類中,因此做到了相互的隔離戏羽,但是不包含樣式担神。 -
React
引用方式遵循ES6
標(biāo)準(zhǔn)
官方在React
組件構(gòu)建上提供了3種不同的方法:React.createClass
,ES6 classes
和無狀態(tài)函數(shù)。
React.createClass
方法是構(gòu)建組件最傳統(tǒng)始花,也是兼容性最好的方法妄讯,實(shí)例代碼如下:
const Button = React.createClass({
getDefaultProps(){
return {
color:'red',
text:'cancle',
};
},
render(){
const {color, text} = this.props;
return (
<button className ={`btn btn - ${color}`}>
<em>{text}</em>
</button>
);
}
});
當(dāng)組件需要調(diào)用Button組件的時(shí)候,只需要寫<Button />
,就可以被解析成React.createElement(Button)
方法來創(chuàng)建Button
實(shí)例酷宵,這意味著在一個(gè)應(yīng)用中調(diào)用幾次Button
亥贸,就會(huì)創(chuàng)建幾次Button
的實(shí)例。
ES6 classes
ES6 classes
的寫法是通過ES6
標(biāo)準(zhǔn)的類語法的方式來構(gòu)建方法:
import React, {Component } from 'react';
class Button extends Component{
constructor (props){
super(props);
}
static defaultProps ={ // 用來設(shè)置默認(rèn)屬性
color:'blue',
text:'Confirm',
};
render(){
const {color,text} = this.props;
return (
<button className = {`btn btn-${color}`}>
<em>{text}</em>
</button>
);
}
}
這里的直觀感受是從調(diào)用內(nèi)部方法變成了類來實(shí)現(xiàn)浇垦,與createClass
的結(jié)果相同的是炕置,調(diào)用類實(shí)現(xiàn)的組件會(huì)創(chuàng)建實(shí)例對(duì)象。在React
組件開發(fā)中,常用的方式是將組件拆分到合理的粒度朴摊,用組合的方式合成業(yè)務(wù)組件默垄。
無狀態(tài)函數(shù)
使用無狀態(tài)函數(shù)構(gòu)建的組件稱為無狀態(tài)組件,這樣的寫法比較受官方推崇甚纲。我們看一下示例代碼:
function Button({color = 'blue',text = 'confirm'}){
return (
<button className = {`btn btn-${color}`}>
<em>{text}</em>
</button>
);
}
無狀態(tài)組件只傳入props
和context
兩個(gè)參數(shù)口锭;也就是說,它不存在state
介杆,也沒有生命周期方法鹃操,組件本身即上面兩種React
組件構(gòu)建方法中的render
方法。不過这溅,像propTypes
和defaultProps
還是可以通過向方法設(shè)置靜態(tài)屬性來實(shí)現(xiàn)组民。
我們使用React
實(shí)現(xiàn)Tabs
組件:
import React,{Component悲靴,PropType} from 'react';
class Tabs extends Component {
constructor(props){
super(props);
}
//...
render(){
return <div className = 'ui-tabs'></div>
}
};
export defaults Tabs;