由於工做須要,這段時間一直在看React相關的東西,不得不感嘆Facebook在開源項目和軟件架構方面的實力,其在React中提出的一些設計思想很是新穎,極大的簡化了前端開發的代碼邏輯。本文將介紹React相關的基礎知識,以及本人在學習過程發現的好的學習資料。javascript
React是Facebook開源的一套用來建立用戶界面的JS庫,它重在界面渲染,所以不少人認爲React是傳統MVC中的V(視圖),使用React你能夠輕鬆構建可交互、基於狀態的、可複用的UI組件。html
Facebook建立React的初衷是想使得構建隨着時間流逝數據不斷變化的大規模應用程序變得簡單,Facebook工程師認爲傳統的MVC模式已經不適用於構建這種大規模應用,由於當系統中的模型和對應的視圖愈來愈多時,其複雜程度就會迅速擴大,加之可能存在的雙向數據流動,致使程序難以理解和調試。前端
React有兩個主要思想:java
簡單
僅僅表達出你的應用在任意時間點應該呈現的樣子(這種展示是能夠預測的,給編寫測試代碼帶來了極大的便利),數據驅動UI,當底層數據變了,React會自動處理全部用戶界面的更新,經過Dom Diff算法儘量少的減小Dom變化以提升性能。react
聲明式
當數據(狀態)變化時,React內部知道該怎樣去局部更新須要變化的部分視圖。也就是說在在編程時咱們只須要告訴React想要的是什麼,而不須要告訴React怎麼樣一步步Dom操做才能到達須要的效果。能夠參見這裏關於聲明式和命令式編程的區別。webpack
選擇React無非是看中了它所表現出的突出優勢:ios
組件化思想,使應用更加容易維護和複用git
Virtual Dom使得React不只能夠在瀏覽器端渲染也能夠運行在服務端,這爲編寫同構應用提供了可能es6
Dom Diff算法儘量的減小Dom操做,提升應用的性能github
單向數據流使應用邏輯可容易理解,基於狀態的視圖更新使應用狀態可預測,便於測試
固然React也不是完美的,它的JSX語法雖然提供了強大的功能,但它卻將HTML結構分散進了JS文件中,不利於初學者對網頁總體結構的把握,同時Css-in-js的寫法也背離了Web標準倡導的表現結構邏輯分離的思想。如何取捨還要看實際狀況。
想要快速開始學習React,官方tutorial是個不錯的選擇,上面包含了構建React組件的關鍵性內容。若是你想親手敲兩行代碼體驗一下,你能夠下載一個starter kit,裏面包含了相關依賴文件和一些實例,固然你也可使用jsfiddle在線體驗。
JSX是React提供的用來快速建立React樹節點的語法糖,它可以使用相似HTML的語法建立JavaScript對象,固然你也可使用提供的api手動建立。
例如咱們事先建立了一個Nav組件,那麼在對應的Dom節點渲染它時就能夠像下面同樣:
var navElement = <Nav className='nav' />; //jsx語法,react會自動將其轉換成javascript 對象 ReactDOM.render(navElement, /*真實dom節點*/); //渲染
JSX語法的一個重要特色是可以使用JavaScript表達式,經過在屬性值或子組件混入js表達式,可以輕易的寫出更加複雜的組件,js表達式須要用一對大括號{}包裹起來。
例如屬性值混入js表達式:
//顯示不一樣的樣式類 var person = <Person className={window.isLoggedIn ? 'logged' : null />; //輸入框禁止輸入 var input = <input type='button' disabled={false} />;
子組件混入js表達式:
//根據isLoggedIn的值嵌入不一樣的子組件 var content = <Container> {window.isLoggedIn ? <Nav /> : <Login />}</Container>; //數組循環建立多個子組件,key屬性不能省略,不然會報錯 var results = [1, 2, 3, 4]; var list = <ol> {results.map(function(result, index) { return <li key={index}>{result}</li>; })} </ol>
JSX既能解析React組件標籤也能解析HTML標籤,可是React組件必須是首字母大寫,如上面的Container;HTML標籤則照常小寫便可,如ol
style屬性值必須是JavaScript對象
JSX最外層的標籤必須是惟一的,若是有多個能夠用div標籤將其包裹起來
由於JSX自己是JavaScript,HTML一些與JavaScript關鍵字有衝突的屬性,如class、for都要轉換成相應的className、htmlFor,更多不一樣參見jsx-gotchas
循環建立多個同類子組件的時候,要帶上key屬性,且key值是惟一的,如上例的多個li標籤
React提倡組件化思想,認爲一個應用應該是多個互相獨立的組件構成的大組件,每一個組件只關心本身部分的邏輯。以下圖的評論界面所示,一個評論組件CommentBoxComponent由CommentListComponent和FormBoxComponent組件組成,相應的CommentListComponent組件又由CommentItemComponent和ButtonComponent組成。
對於初學者而言,想要很好的對UI進行組件劃分可能比較困難,可是遵循一些組件劃分原則是有益的:
單一職責,一個組件應該只作一件事情,當你發如今一個組件作了太多事情的時候,應該考慮將其拆分爲更小的子組件。
根據數據模型拆分組件,由於React是基於數據來渲染UI,因此讓你的組件僅僅是用來表現數據模型的某個部分一般是正確的選擇。
構建純組件,一個純組件一般沒有內部狀態(state,後面會講到),它用來渲染的數據徹底來自於輸入的props,使用相同的props來渲染相同的純組件屢次將獲得相同的UI,不存在內部狀態致使渲染不一樣。
React提供了createClass來建立組件,它接受一個對象做爲參數,該對象包含一些屬性和函數來具體描述一個組件,其中render函數是必須的,其餘的狀態初始化函數以及生命週期相關的函數都是可選的:
//注意Component首字母大寫 var Component = React.createClass({ getIntialState: function(){}, //初始化組件狀態 getDefaultProps: function(){}, //初始化組件的默認屬性 propTypes: {}, //規定屬性的存在性和類型 //一些生命週期相關函數 componentWillMount: function(){}, //組件被嵌入以前觸發 componentDidMount: function(){}, //組件被嵌入以後觸發 componentWillReceiveProps: function(){}, //當props有改變時觸發 componentWillUnmount: function(){}, //組件被註銷以前觸發 //渲染函數,不能省略 render: function() { return <h1>Hello </h1> ; } });
以上是ES5的寫法,若是你看了一些腳手架項目,你會發現有些使用了ES6的語法,ES6建立組件的語法有很大的不一樣:
class Component extends React.Component { constructor() { super(); this.state = { //組件狀態 }; } static defaultProps = { //組件屬性 }; render() { return ( <div onClick={this.handleClick}> You {text} this. Click to toggle. </div> ); } }
咱們能夠看到使用了ES6語法的組件構建很像在編寫面向對象編程時建立類,更多寫法的不一樣,能夠參見es5-es6寫法對照表。
前面咱們有涉及props和state這個兩個概念,這裏作一下解釋。
當咱們在使用定義好的組件時,能夠向其添加一些屬性,在組件定義的內部,能夠經過this.props來訪問這些屬性,以下在render方法裏渲染動態數據:
var Component = React.createClass({ getDefaultProps: function(){ return { name: 'world' } }, propTypes: { name: React.PropTypes.string //設置屬性的類型 }, render: function(){ return ( <h1>Hello, {this.props.name}!</h1> //訪問name屬性 ); } }); ReactDOM.render(<Component name="Handsome" />, document.body);
其中getDefaultProps用來設置默認的屬性值,propTypes來設置屬性的類型,在使用時若是屬性類型不匹配會提示。
this.props是隻讀的,它一般用來傳遞來自父組件的數據,也是React構建單向數據流的方式。
相同的組件之因此可以表現出不同的UI是由於它們內部擁有不一樣的狀態(states),每一個組件均可以擁有本身的state,而且能夠在須要的時候經過props傳遞給子組件。組件能夠經過setState函數來修改內部的狀態,同時觸發界面的渲染。
var ParentComponent = React.createClass({ getInitialState: function(){ return { name: 'Tyler McGinnis', friend: 'Tom' } }, handleClick: function(e){ this.setState({name: 'Tim'}); //更改狀態 }, render: function(){ return ( <div> <h3> Name: {this.state.name} </h3> //點擊觸發事件,調用handleClick改變組件狀態 <button onClick={this.hanleClick}>change name</button> <Component name={this.state.friend} /> //傳遞狀態到子組件 </div> ) } });
這裏須要注意的是getInitialState是用來初始化組件內部狀態的默認值,不要在該方法裏面使用this.props,除非某個屬性有明確的語義是被用來初始化state的,詳細請參看這裏。
props是隻讀的,不可以在組件內部修改,它是父組件向子組件傳遞數據的途徑;state是組件自身的狀態,它不能是父組件傳遞過來的數據,而且state是能夠改變的。
合理的狀態操做是建立多個只負責渲染數據的無狀態(stateless)組件,在它們的上層建立一個有狀態(stateful)組件並把它的狀態經過 props 傳給子組件。這個有狀態的組件封裝了全部用戶的交互邏輯,而這些無狀態組件則負責聲明式地渲染數據。
如前面組件建立裏提到,組件建立時能夠提供幾個生命週期函數,這些函數決定了組件在不一樣的時期進行的操做。
componentWillMount: 在初始化渲染執行前當即調用且僅調用一次。若是在這個方法內部調用setState並不會觸發從新渲染,你能夠將一些只須要執行一次的操做放在這個函數裏。
componentDidMount:在初始化渲染以後,當即調用一次,這個時候你能夠訪問虛擬Dom節點。咱們能夠在這個方法中與其餘JavaScript框架進行集成、處理一些渲染後的邏輯(好比說綁定一些事件等)、發送Ajax請求或是設置定時器方法(setTimeout/setInterval)等。
componentWillReceiveProps:初始化渲染時不會被調用,只有當props放生改變時纔會被調用。該方法能夠做爲React在prop傳入以後,render()方法執行以前更新state的合適時機。舊的props能夠經過this.props獲取到。
componentWillUnmount:在組件從DOM中移除的時候馬上被調用咱們能夠在該方法中執行任何須要的清理,好比無效的定時器,或者清除在componentDidMount()中建立的DOM元素等。
另外React還提供了一個用來優化渲染的周期函數shouldComponentUpdate,它能夠用來判斷一次狀態改變是否須要從新渲染,更多生命週期函數介紹參見這裏
React有內建的跨瀏覽器的事件系統,你能夠在組件裏以添加屬性的方式綁定事件和相應的處理函數,如上面例子中ParentComponent組件裏經過設置onClick屬性綁定事件的處理函數handleClick。這種事件綁定方法極大的方便了事件操做,不用再像之前先定位到Dom節點,再經過addEventListener綁定事件,還要用removeEventListener解綁。當組件註銷時,react會自動幫咱們解綁事件。更多React支持的事件,請參見這裏。
若是你是剛剛接觸React,那麼當你閱讀官方的tutorial文檔時,會以爲這玩意原來這麼簡單,無非是將頁面功能組件化,調用爲數很少的幾個api,按照教程一步一步來很快就編寫出一個評論應用。當你想利用腳手架快速搭建企業級的React開發環境時,你會也許會用到react-starter-kit,可是他卻有點「名不符實」,由於匱乏的文檔說明,讓其對新手並不友好。相比之下react-redux-universal-hot-example則更加易於理解和學習。值得注意的是學習React,僅僅是學習框架自己是不夠,由於當你閱讀代碼的過程當中,你會發現npm是基本的;webpack也是必須的;你還要知道ES6相關語法,相應的你要懂得使用Babel來轉換ES5;更進階你要開始學習全新的程序設計模式Flux和Redux來管理應用的狀態等等。學習這些知識不可能一蹴而就,當你遇到某個解不開的點時,不妨先跳過,隨着學習的深刻,當你回頭來看時就會有種恍然大悟的感受。
The Only React.js Tutorials and Resources You’ll Need,介紹了不少React學校相關的資源,上面的每篇文章都值得一讀。
React的一些概念對React的一些概念進行了闡述。
React.js Tutorial Pt 1: A Comprehensive Guide to Building Apps with React.js 很是不錯的tutorial,做者思路很清晰,一步步講解而且附有實例,系列文章還沒更新完
React 入門實例教程,阮一峯寫的實例教程,裏面包含了各個關鍵知識點的實例代碼。
es5-es6語法對比 ,比較詳細的react es5-es6語法對照表,看完它對理解一些項目代碼比較有用
react style guide,react 代碼書寫風格的一篇文章,遵照你們都在用的一些規則,對閱讀源碼頗有幫助。
淺談 React、Flux 與 Redux,對React、Flux、Redux之間的關係進行了很好的闡述。
Full-Stack Redux Tutorial,這篇文章介紹瞭如何使用Redux構建同構應用,經過一個投票應用,全面介紹了整個開發流程,很是值得閱讀。