react簡(jiǎn)介
React 起源于 Facebook 的內(nèi)部項(xiàng)目狗超,因?yàn)樵摴緦?duì)市場(chǎng)上所有 JavaScript MVC 框架,都不滿意,就決定自己寫一套恕曲,用來(lái)架設(shè)Instagram 的網(wǎng)站切心。做出來(lái)以后飒筑,發(fā)現(xiàn)這套東西很好用,就在2013年5月開源了绽昏。
由于 React的設(shè)計(jì)思想極其獨(dú)特协屡,屬于革命性創(chuàng)新,性能出眾全谤,代碼邏輯卻非常簡(jiǎn)單肤晓。所以,越來(lái)越多的人開始關(guān)注和使用认然,認(rèn)為它可能是將來(lái) Web 開發(fā)的主流工具补憾。
這個(gè)項(xiàng)目本身也越滾越大,從最早的UI引擎變成了一整套前后端通吃的 Web App 解決方案季眷。衍生的 React Native 項(xiàng)目余蟹,目標(biāo)更是宏偉,希望用寫 Web App 的方式去寫 Native App子刮。如果能夠?qū)崿F(xiàn)威酒,整個(gè)互聯(lián)網(wǎng)行業(yè)都會(huì)被顛覆,因?yàn)橥唤M人只需要寫一次 UI 挺峡,就能同時(shí)運(yùn)行在服務(wù)器葵孤、瀏覽器和手機(jī)。
特點(diǎn):
- 聲明式設(shè)計(jì):React采用聲明范式橱赠,可以輕松描述應(yīng)用尤仍。
- 高效:React通過(guò)對(duì)DOM的模擬,最大限度地減少與DOM的交互狭姨。
- 靈活:React可以與已知的庫(kù)或框架很好地配合宰啦。
一些好的學(xué)習(xí)途徑:
react入門知識(shí)儲(chǔ)備
ES6
react推薦使用ES6語(yǔ)法,如果你已經(jīng)熟悉ES6饼拍,那就最好去使用ES6赡模。
但如果你并不很了解,使用之前的ES語(yǔ)法也是可以的师抄,但在此之前漓柑,你一定要先了解ES6的 const,let 以及 箭頭函數(shù)。
Webpack & Babel
Babel用于將ES6及jsx語(yǔ)法翻譯成瀏覽器可以識(shí)別渲染的語(yǔ)法辆布,而Webpack則用于將這一過(guò)程自動(dòng)化瞬矩,從而提高開發(fā)效率。
前期學(xué)習(xí)過(guò)程中可以借助腳手架去配置Webpack和Babel锋玲,但是要試著去看懂理解他們的配置景用,逐漸去擺脫腳手架的束縛。
react兩種前端使用方法
直接使用
通過(guò)script標(biāo)簽引入
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello React!</title>
<script src="https://cdn.bootcss.com/react/15.4.2/react.min.js"></script>
<script src="https://cdn.bootcss.com/react/15.4.2/react-dom.min.js"></script>
<script src="https://cdn.bootcss.com/babel-standalone/6.22.1/babel.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>
注意:
- 最后一個(gè)
<script>
標(biāo)簽的 type 屬性為text/babel
嫩絮。這是因?yàn)?React 獨(dú)有的 JSX 語(yǔ)法丛肢,跟 JavaScript 不兼容。凡是使用 JSX 的地方剿干,都要加上type="text/babel"
蜂怎。 - 上面代碼一共用了三個(gè)庫(kù): react.js 、react-dom.js 和 Browser.js 置尔,它們必須首先加載杠步。
webpack打包編譯
安裝node環(huán)境,使用npm安裝依賴榜轿,創(chuàng)建項(xiàng)目幽歼,配置webpack,babel谬盐。甸私。。
這里不再贅述飞傀,不會(huì)的可以參考這篇博文webpack入門+react環(huán)境配置
每次開發(fā)都要去配置太麻煩了皇型,熟悉webpack之后我們可以使用腳手架快速搭建開發(fā)環(huán)境
關(guān)于react腳手架的匯總和使用可以參考我的另一篇博文快速構(gòu)建React+Webpack+ES6項(xiàng)目
JSX語(yǔ)法及組件
JSX
React 使用 JSX 來(lái)替代常規(guī)的 JavaScript。
JSX 的基本語(yǔ)法規(guī)則:遇到 HTML 標(biāo)簽(以 <
開頭)砸烦,就用 HTML 規(guī)則解析弃鸦;遇到代碼塊(以 {
開頭),就用 JavaScript 規(guī)則解析幢痘。
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example'),
function () {
console.log('渲染結(jié)束回調(diào)函數(shù)在這里!')
}
);
JSX語(yǔ)法具備以下特點(diǎn):
- 可以在 JSX 中使用 JavaScript 表達(dá)式唬格。表達(dá)式寫在花括號(hào) {} 中。
- 在 JSX 中不能使用 if else 語(yǔ)句颜说,但可以使用 conditional (三元運(yùn)算) 表達(dá)式來(lái)替代购岗,這一點(diǎn)官方文檔有詳細(xì)說(shuō)明。
- React 推薦使用內(nèi)聯(lián)樣式门粪,但是這里內(nèi)聯(lián)樣式作為對(duì)象的形勢(shì)藕畔,使用{}包裹起來(lái)。
- JSX 允許直接在模板插入 JavaScript 變量庄拇。如果這個(gè)變量是一個(gè)數(shù)組,則會(huì)展開這個(gè)數(shù)組的所有成員(數(shù)組中的每一項(xiàng)元素都需要添加一個(gè)key屬性)。
- JSX的注釋使用
/* ... */
寫在{}中措近。
tip:在jsx中給標(biāo)簽添加屬性需要注意溶弟, class
屬性需要寫成 className
,for
屬性需要寫成 htmlFor
瞭郑,這是因?yàn)?class
和 for
是 JavaScript 的保留字辜御。
具體效果我們將在后面演示的代碼中體現(xiàn)。
組件
React 允許將代碼封裝成組件(component)屈张,然后像插入普通 HTML 標(biāo)簽一樣擒权,在網(wǎng)頁(yè)中插入這個(gè)組件,官方是這么說(shuō)的阁谆。但是實(shí)際上我們實(shí)際的業(yè)務(wù)代碼基本都是一個(gè)又一個(gè)的組件堆砌而成碳抄,這樣做有很多好處。首先得益于react的局部刷新场绿,每次更新頁(yè)面內(nèi)容時(shí)我們只需操作和更新對(duì)應(yīng)的組件即可剖效,無(wú)需對(duì)整個(gè)頁(yè)面進(jìn)行重新渲染。組件使頁(yè)面模塊化焰盗,結(jié)構(gòu)更加清晰璧尸。此外組件提高了代碼的復(fù)用率,提高編碼效率......
react使用React.createClass 方法生成一個(gè)組件類熬拒。
var HelloMessage = React.createClass({
render: function() {
return <h1>Hello World!</h1>
}
});
ReactDOM.render(
<HelloMessage />,
document.getElementById('example')
);
上面就是一個(gè)簡(jiǎn)單的HelloMessage組件爷光,這里需要注意:
- 組件類的第一個(gè)字母必須大寫,jsx使用標(biāo)簽首字母的大小寫來(lái)區(qū)分原生標(biāo)簽和組件澎粟,上面代碼中的HelloMessage組件如果命名為helloMessage蛀序,ReactDOM在渲染時(shí)會(huì)認(rèn)為這是一個(gè)HTML原生標(biāo)簽,從而導(dǎo)致渲染失敗捌议。
- 組件類只能包含一個(gè)頂層標(biāo)簽 哼拔,這個(gè)意思就是每一個(gè)組件必須要包裹在一個(gè)標(biāo)簽內(nèi),如果上面的代碼寫成
return (<h1>Hello World!</h1><h2>Hello React!</h2>)
瓣颅,即一個(gè)組件內(nèi)存在兩個(gè)頂層標(biāo)簽倦逐,這樣是不被允許的。
組件允許嵌套宫补,即一個(gè)組件內(nèi)嵌套另一個(gè)組件:
var HelloMessage = React.createClass({
render: function() {
return (
<div>
<h1>Hello World!</h1>
<MessageBox/>
</div>
)
}
});
var MessageBox = React.createClass({
render: function() {
return <h3>Hello React!</h3>
}
})
ReactDOM.render(
<HelloMessage />,
document.getElementById('example')
);
上面代碼我們可以看到我們創(chuàng)建了一個(gè)新的組件MessageBox檬姥,并把它放在了HelloMeaasge組件中。同時(shí)大家也會(huì)注意到粉怕,我在HelloMessage的return中放了一個(gè)div包裹整個(gè)組件內(nèi)容健民,這也是上面提到的組件只能有一個(gè)頂層標(biāo)簽的原因。另外標(biāo)簽一定注意閉合贫贝,包括組件標(biāo)簽秉犹,不然會(huì)報(bào)錯(cuò)不能正常渲染蛉谜。瀏覽器中運(yùn)行如下:
上面說(shuō)到JSX的時(shí)候我提到了jsx可以自動(dòng)展開數(shù)組,這里我們來(lái)試一下:
var HelloMessage = React.createClass({
render: function() {
var arr= [];
for (var i = 0; i < 5; i++) {
arr.push(<MessageBox key={i}/>)
}
return (
<div>
<h1>Hello World!</h1>
{arr}
</div>
)
}
});
var MessageBox = React.createClass({
render: function() {
return <h3>Hello React!</h3>
}
})
ReactDOM.render(
<HelloMessage />,
document.getElementById('example')
);
這里我們創(chuàng)建一個(gè)數(shù)組崇堵,使用for循環(huán)把組件MessageBox循環(huán)五遍放進(jìn)數(shù)組中型诚,而在HelloMessage組件中我們僅僅使用花括號(hào)來(lái)包裹數(shù)組,react在解析時(shí)就會(huì)把這個(gè)arr作為js變量來(lái)解析鸳劳,發(fā)現(xiàn)它是數(shù)組就直接展開數(shù)組內(nèi)容狰贯。運(yùn)行結(jié)果如下:
具體組件中的數(shù)據(jù)傳遞,我們將在下節(jié)中講到赏廓。
react數(shù)據(jù)載體
react中的數(shù)據(jù)載體有三個(gè):state涵紊,props 和 context。他們?cè)趓eact起著重要的作用幔摸。
State
React 里主要使用state來(lái)定義組件內(nèi)部狀態(tài)摸柄。
在頁(yè)面中我們只需更新組件的 state,然后用戶界面就會(huì)根據(jù)我們的設(shè)定重新渲染抚太。
來(lái)看下面的例子:
var LikeButton = React.createClass({
getInitialState: function() {
return {liked: false};
},
handleClick: function(event) {
this.setState({liked: !this.state.liked});
},
render: function() {
var text = this.state.liked ? 'like' : 'haven\'t liked';
return (
<p onClick={this.handleClick}>
You {text} this. Click to toggle.
</p>
);
}
});
ReactDOM.render(
<LikeButton />,
document.getElementById('example')
);
這段代碼中我們首先定義了一個(gè)LikeButton組件塘幅,使用getInitialState方法定義初始狀態(tài),即一個(gè)對(duì)象尿贫,對(duì)象中的值可以通過(guò)this.state.liked獲取电媳。然后我們給p標(biāo)簽綁定一個(gè)點(diǎn)擊事件handleClick,當(dāng)用戶點(diǎn)擊時(shí)通過(guò)this.setState方法去改變liked的值庆亡。當(dāng)react發(fā)現(xiàn)state的值發(fā)生改變匾乓,就會(huì)重新調(diào)用this.render方法重新渲染組件。細(xì)心的同學(xué)可能會(huì)注意到j(luò)sx中不能使用if又谋,所以這里使用了三元運(yùn)算符來(lái)改變text的值拼缝。
我們可以通過(guò)定義一個(gè)變量來(lái)獲取render:
var likeButton= ReactDOM.render(
<LikeButton />,
document.getElementById('example')
);
在控制臺(tái)中你會(huì)看到render返回的一個(gè)對(duì)象,里面包括了context彰亥,props咧七,state這些值以及handleClick這樣的事件等。這里可以看到state是一個(gè)對(duì)象任斋,如果我們直接去改變這個(gè)state继阻,雖然可以成功改變,但是你會(huì)發(fā)現(xiàn)頁(yè)面沒(méi)有任何變化:
在react中废酷,state方法主要用于數(shù)據(jù)的調(diào)用瘟檩,此時(shí)雖然數(shù)據(jù)更改了但是不會(huì)自動(dòng)的使頁(yè)面得到更新,而官方則給出了forceUpdate()方法去手動(dòng)更新頁(yè)面澈蟆。所以在實(shí)際的項(xiàng)目中可以根據(jù)需求來(lái)決定使用setState來(lái)自動(dòng)更新頁(yè)面墨辛,還是使用state+forceUpdate。
Props & Context
props和context比較相似趴俘,是用于組件之間通信睹簇,不同的是props只能逐層傳遞奏赘,但是content可以跨組件傳遞。
雖然context很強(qiáng)大带膀,但是React官方文檔卻不推薦使用志珍,首先props可以讓你看到哪些數(shù)據(jù)在傳遞,可以使代碼更易讀垛叨,context則不然;其次context是react一個(gè)實(shí)驗(yàn)性API柜某,有可能在未來(lái)的版本中移除嗽元。
在一般的項(xiàng)目中,簡(jiǎn)單的數(shù)據(jù)傳遞一般使用props喂击,而復(fù)雜狀態(tài)則使用Redux 或MobX狀態(tài)管理庫(kù)剂癌。
所以這里著重來(lái)說(shuō)一下props,而對(duì)context感興趣的童鞋可以去看這篇博客:React 中 context 的使用
首先來(lái)寫一個(gè)簡(jiǎn)單的demo:
var Button = React.createClass({
render: function() {
return (
<button style={{background: this.props.color}}>刪除</button>
);
}
});
var Message= React.createClass({
render: function() {
var test = [];
var color = this.props.color;
this.props.text.forEach(function(msg,index){
test.push(<p key={index}>{msg}<Button color={color}/></p>)
});
return (
<div>{test}</div>
)
}
})
var message = ReactDOM.render(
<Message text={["這是一段文字","這是另一段文字"]} color={"red"}/>,
document.getElementById('example')
);
這段代碼首先創(chuàng)建一個(gè)Button組件翰绊,按鈕的顏色定義為props佩谷。然后Button被嵌套進(jìn)Message組件中。實(shí)際渲染時(shí)我們?cè)?<Mesaage/>
中定義text和color的值监嗜,Message組件接收并將color傳遞給Button組件谐檀,同時(shí)使用forEach循環(huán)text數(shù)組。但是如果傳來(lái)的text不是一個(gè)數(shù)組裁奇,那么forEach肯定會(huì)報(bào)錯(cuò)桐猬,這里就需要用到props的數(shù)據(jù)驗(yàn)證:
var Message= React.createClass({
propTypes: {
text: React.PropTypes.array,
},
getDefaultProps:function() {
return {
text: ["默認(rèn)的消息"]
}
},
render: function() {
var test = [];
var color = this.props.color;
this.props.text.forEach(function(msg,index){
test.push(<p key={index}>{msg}<Button color={color}/></p>)
});
return (
<div>{test}</div>
)
}
})
這里給Message組件加了兩個(gè)一個(gè)propTypes用于驗(yàn)證props的值類型,也可以在array后加.isRequire
規(guī)定text值不能為空刽肠。以及getDefaultProps用于定義props的默認(rèn)值溃肪。但是這里注意一點(diǎn),出于性能原因音五,propTypes
僅在開發(fā)模式下檢查惫撰。更多propTypes的驗(yàn)證類型參考官網(wǎng)文檔。