JSX是React的核心組成部分兰粉,它使用XML標(biāo)記的方式去直接聲明界面棚赔,界面組件之間可以互相嵌套单寂∑床裕可以理解為在JS中編寫與XML類似的語言,一種定義帶屬性樹結(jié)構(gòu)(DOM結(jié)構(gòu))的語法笑诅,它的目的不是要在瀏覽器或者引擎中實現(xiàn),它的目的是通過各種編譯器將這些標(biāo)記編譯成標(biāo)準(zhǔn)的JS語言疮鲫。
雖然你可以完全不使用JSX語法吆你,只使用JS語法,但還是推薦使用JSX俊犯,可以定義包含屬性的樹狀結(jié)構(gòu)的語法妇多,類似HTML標(biāo)簽?zāi)菢拥氖褂茫腋阌诖a的閱讀燕侠。
使用JSX語法后者祖,你必須要引入babel的JSX解析器,把JSX轉(zhuǎn)化成JS語法绢彤,這個工作會由babel自動完成七问。同時引入babel后,你就可以使用新的es6語法茫舶,babel會幫你把es6語法轉(zhuǎn)化成es5語法械巡,兼容更多的瀏覽器。
我們從最簡單的一個官網(wǎng)例子helloworld開始:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello React!</title>
<script src="vendor-js/react.js"></script>
<script src="vendor-js/react-dom.js"></script>
<script src="vendor-js/babel-core/browser.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
</script>
</body>
</html>
在這個簡單的例子中姆涩,看不出來有任何jsx語法的地方矫废,當(dāng)其中<h1>Hello,world</h1>
就是使用到了jsx語法蚪缀。HTML 語言直接寫在 JavaScript 語言之中,不加任何引號古程,這就是 JSX 的語法,它允許 HTML 與 JavaScript 的混寫喊崖。如果轉(zhuǎn)化成純JavaScript 的話挣磨,就是:
<script type="text/javascript">
ReactDOM.render(
React.DOM.h1(null,'hello,world!'),
document.getElementById('example')
);
</script>
在上述JSX語法中有兩個要注意的地方:
- <script> 標(biāo)簽的 type 屬性為 text/babel,這是React 獨有的 JSX 語法贷祈,跟 JavaScript 不兼容趋急。凡是在頁面中直接使用 JSX 的地方,都要加上 type="text/babel"势誊。
- 一共用了三個庫: react.js 呜达、react-dom.js 和 browser.min.js ,它們必須首先加載粟耻。其中查近,react.js 是 React 的核心庫眉踱,react-dom.js 是提供與 DOM 相關(guān)的功能, browser.min.js的作用是將 JSX 語法轉(zhuǎn)為 JavaScript 語法霜威。
將 JSX 語法轉(zhuǎn)為 JavaScript 語法谈喳,這一步很消耗時間。現(xiàn)在前端項目戈泼,都會使用前端工程化婿禽,不會直接在html頁面中直接寫js代碼,寫好的js代碼都會使用工具進(jìn)行編譯壓縮等大猛。這樣的話扭倾,我們的jsx也會通過編譯直接轉(zhuǎn)化成js語法,讓瀏覽器直接使用挽绩。
ReactDOM.render 是 React 的最基本方法膛壹,將模板轉(zhuǎn)為HTML語言,并插入指定的 DOM 節(jié)點唉堪。
JSX的特點:
- 類XML語法容易接受模聋,結(jié)構(gòu)清晰
- 增強(qiáng)JS語義
- 抽象程度高,屏蔽DOM操作唠亚,跨平臺
- 代碼模塊化
JSX基本語法規(guī)則:
JSX本身就和XML語法類似链方,可以定義屬性以及子元素。唯一特殊的是可以用大括號來加入JavaScript表達(dá)式趾撵。遇到 HTML 標(biāo)簽(以 < 開頭)侄柔,就用 HTML 規(guī)則解析;遇到代碼塊(以 { 開頭)占调,就用 JavaScript 規(guī)則解析暂题。
var arr = [
<h1>Hello world!</h1>,
<h2>React is awesome</h2>,
];
ReactDOM.render(
<div>{arr}</div>,
document.getElementById('example')
);
這個就是一個簡單的html與js混用的例子。arr變量中存在html元素究珊,div中又使用了arr這個js變量薪者。轉(zhuǎn)化成純javascript的話:
var h1=React.DOM.h1(null,'Hello world!');
var h2=React.DOM.h1(null,'React is awesome');
var div=React.DOM.div(null,h1,h2);
ReactDOM.render(
div,
document.getElementById('example')
);
React組件
我們使用jsx來將代碼封裝成React組件,然后像插入普通 HTML 標(biāo)簽一樣剿涮,在其他地方插入這個組件言津。使用React.createClass用于生成一個組件。
var MyComponent=React.createClass({
render: function() {
return <h1>Hello world!</h1>;
}
});
ReactDOM.render(
<MyComponent />,
document.getElementById('example')
);
上面代碼中取试,變量 MyComponent就是一個組件類悬槽。模板插入 <MyComponent /> 時,會自動生成 MyComponent 的一個實例(下文的"組件"都指組件類的實例)瞬浓。所有組件類都必須有自己的 render 方法初婆,用于輸出組件。
React 可以渲染 HTML 標(biāo)簽 (strings) 或 React 組件 (classes)。
- 在react中通常約定組件類的第一個字母必須大寫磅叛,html標(biāo)簽都是小寫屑咳。
//要渲染 HTML 標(biāo)簽,只需在 JSX 里使用小寫字母開頭的標(biāo)簽名弊琴。
var myDivElement = <div className="foo" />;
React.render(myDivElement, document.getElementById('example'));
//要渲染 React 組件兆龙,只需創(chuàng)建一個大寫字母開頭的本地變量。
var MyComponent = React.createClass({/.../});
var myElement = <MyComponent />;
React.render(myElement, document.getElementById('example'));
* 還有一個注意點:組件類只能包含一個頂層標(biāo)簽敲董,否則會報錯紫皇。 ```javascript
//var myDivElement =<h1>你好</h1><h1>hello</h1>;
//上述寫法是會報錯的,要寫成只有一個頂層標(biāo)簽:
var myDivElement =<div><h1>你好</h1><h1>hello</h1></div>;
上述代碼一個靜態(tài)的組件臣缀,下面看一個動態(tài)組件:
var MyComponent=React.createClass({
getInitialState: function() {
return {clickNum: 0};
},
handleClick:function(){
var num=this.state.clickNum;
num++;
this.setState({clickNum:num});
},
render: function() {
return (
<div>
<h1 onClick={this.handleClick}>Hello {this.props.name}!</h1>
<h2 style={{color:'red'}}>點擊{this.props.name}次數(shù):{this.state.clickNum}</h2>
</div>
);
}
});
ReactDOM.render(
<div>
<MyComponent name="張三" />
<hr/>
<MyComponent name="李四" />
</div>,
document.getElementById('example')
);
上面代碼中定義的MyComponent組件包含屬性坝橡,狀態(tài)和事件泻帮,是一個簡單的比較完整的組件精置。使用props通過父組件進(jìn)行傳遞值,使用state定義組件自己的狀態(tài)锣杂,組件支持的大部分的DOM操作事件脂倦。
關(guān)于屬性props:
- class 屬性需要寫成 className ,for 屬性需要寫成 htmlFor 元莫,這是因為 class 和 for 是 JavaScript 的保留字赖阻。
- 直接在標(biāo)簽上使用style屬性時,要寫成style={{}}是兩個大括號踱蠢,外層大括號是告知jsx這里是js語法火欧,和真實DOM不同的是,屬性值不能是字符串而必須為對象茎截,需要注意的是屬性名同樣需要駝峰命名法苇侵。即margin-top要寫成marginTop。
- this.props.children 不要children作為把對象的屬性名企锌。因為this.props.children獲取的該標(biāo)簽下的所有子標(biāo)簽榆浓。this.props.children 的值有三種可能:如果當(dāng)前組件沒有子節(jié)點,它就是 undefined ;如果有一個子節(jié)點撕攒,數(shù)據(jù)類型是 object 陡鹃;如果有多個子節(jié)點,數(shù)據(jù)類型就是 array 抖坪。所以萍鲸,處理 this.props.children 的時候要小心。官方建議使用React.Children.map來遍歷子節(jié)點擦俐,而不用擔(dān)心數(shù)據(jù)類型脊阴。
關(guān)于狀態(tài)state:
- 組件免不了要與用戶互動,React 將組件看成是一個狀態(tài)機(jī),一開始有一個初始狀態(tài)蹬叭,然后用戶互動藕咏,導(dǎo)致狀態(tài)變化,從而觸發(fā)重新渲染 UI秽五。
- getInitialState 方法用于定義初始狀態(tài)孽查,也就是一個對象,這個對象可以通過 this.state 屬性讀取坦喘。當(dāng)用戶點擊組件盲再,導(dǎo)致狀態(tài)變化,this.setState 方法就修改狀態(tài)值瓣铣,每次修改以后答朋,自動調(diào)用 this.render 方法,再次渲染組件棠笑。
由于 this.props 和 this.state 都用于描述組件的特性梦碗,可能會產(chǎn)生混淆。一個簡單的區(qū)分方法是蓖救,this.props 表示那些一旦定義洪规,就不再改變的特性,而 this.state 是會隨著用戶互動而產(chǎn)生變化的特性循捺。
注意點:
如果往原生 HTML 元素里傳入 HTML 規(guī)范里不存在的屬性斩例,React 不會顯示它們。如果需要使用自定義屬性从橘,要加 data- 前綴念赶。
<div data-custom-attribute="foo" />
PropTypes
組件的屬性props可以接受任意值,字符串恰力、對象叉谜、函數(shù)等等都可以。有時牺勾,我們需要一種機(jī)制正罢,驗證別人使用組件時,提供的參數(shù)是否符合要求驻民。React中使用PropTypes進(jìn)行參數(shù)的校驗翻具。
var MyTitle = React.createClass({
propTypes: {
title: React.PropTypes.string.isRequired,
},
render: function() {
return <h1> {this.props.title} </h1>;
}
});
上面的Mytitle組件有一個title屬性。PropTypes 告訴 React回还,這個 title 屬性是必須的裆泳,而且它的值必須是字符串。當(dāng)我們給title傳遞一個數(shù)字時柠硕,控制臺就會報錯:
Warning: Failed propType: Invalid prop `title` of type `number` supplied to `MyTitle`, expected `string`.
此外工禾,getDefaultProps 方法可以用來設(shè)置組件屬性的默認(rèn)值运提。
獲取真實的DOM節(jié)點
組件并不是真實的 DOM 節(jié)點,而是存在于內(nèi)存之中的一種數(shù)據(jù)結(jié)構(gòu)闻葵,叫做虛擬 DOM (virtual DOM)民泵。只有當(dāng)它插入文檔以后,才會變成真實的 DOM 槽畔。
有時需要從組件獲取真實 DOM 的節(jié)點栈妆,這時就要用到 ref 屬性。
var MyComponent = React.createClass({
handleClick: function() {
this.refs.myTextInput.focus();
},
render: function() {
return (
<div>
<input type="text" ref="myTextInput" />
<input type="button" value="Focus the text input" onClick={this.handleClick} />
</div>
);
}
});
為了獲取真是DOM節(jié)點厢钧,html元素必須有一個 ref 屬性鳞尔,然后 this.refs.[refName] 就會返回這個真實的 DOM 節(jié)點。需要注意的是早直,由于 this.refs.[refName] 屬性獲取的是真實 DOM 寥假,所以必須等到虛擬 DOM 插入文檔以后,才能使用這個屬性霞扬,否則會報錯糕韧。
求值表達(dá)式
要使用 JavaScript 表達(dá)式作為屬性值,只需把這個表達(dá)式用一對大括號 ( { } ) 包起來祥得,不要用引號 ( " " )兔沃。
在編寫JSX時,在 { } 中不能使用語句(if語句级及、for語句等等),但可以使用求值表達(dá)式额衙,這本身與JSX沒有多大關(guān)系饮焦,是JS中的特性,它是會返回值的表達(dá)式窍侧。我們不能直接使用語句县踢,但可以把語句包裹在函數(shù)求值表達(dá)式中運用。
條件判斷的寫法
你沒法在JSX中使用 if-else 語句伟件,因為 JSX 只是函數(shù)調(diào)用和對象創(chuàng)建的語法糖硼啤。在 { } 中使用,是不合法的JS代碼斧账,不過可以采用三元操作表達(dá)式
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name 谴返? this.props.name : "World"}</div>;
}
});
ReactDOM.render(<HelloMessage name="xiaowang" />, document.body);
可以使用比較運算符“ || ”來書寫,如果左邊的值為真咧织,則直接返回左邊的值嗓袱,否則返回右邊的值,與if的效果相同习绢。
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name || "World"}</div>;
}
});
函數(shù)表達(dá)式
( )有強(qiáng)制運算的作用
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {
(function(obj){
if(obj.props.name)
return obj.props.name
else
return "World"
}(this))
}</div>;
}
});
ReactDOM.render(<HelloMessage name="xiaowang" />, document.body);
外括號“ )”放在外面和里面都可以執(zhí)行渠抹。唯一的區(qū)別是括號放里面執(zhí)行完畢拿到的是函數(shù)的引用蝙昙,然后再調(diào)用“function(){}(this)()”;括號放在外面的時候拿到的事返回值梧却。
組件的生命周期
組件的生命周期分成三個狀態(tài):
* Mounting:已插入真實 DOM
* Updating:正在被重新渲染
* Unmounting:已移出真實 DOM
React 為每個狀態(tài)都提供了兩種處理函數(shù)奇颠,will 函數(shù)在進(jìn)入狀態(tài)之前調(diào)用,did 函數(shù)在進(jìn)入狀態(tài)之后調(diào)用放航,三種狀態(tài)共計五種處理函數(shù)大刊。
* componentWillMount()
* componentDidMount()
* componentWillUpdate(object nextProps, object nextState)
* componentDidUpdate(object prevProps, object prevState)
* componentWillUnmount()
此外,React 還提供兩種特殊狀態(tài)的處理函數(shù)三椿。
* componentWillReceiveProps(object nextProps):已加載組件收到新的參數(shù)時調(diào)用
* shouldComponentUpdate(object nextProps, object nextState):組件判斷是否重新渲染時調(diào)用
注釋
JSX 里添加注釋很容易缺菌;它們只是 JS 表達(dá)式而已。你只需要在一個標(biāo)簽的子節(jié)點內(nèi)(非最外層)小心地用 {} 包圍要注釋的部分搜锰。
{/* 一般注釋, 用 {} 包圍 */}