http://www.cnblogs.com/yc-755909659/p/6526896.htmljavascript
React 能夠靈活的應用在各類各樣的項目中。你能夠用它來建立新的應用程序,你也能夠逐步引用而不改變現有的代碼庫。html
React 起源於 Facebook 的內部項目,由於該公司對市場上全部 JavaScript MVC 框架,都不滿意,就決定本身寫一套,用來架設 Instagram 的網站。作出來之後,發現這套東西很好用,就在2013年5月開源了。java
你能夠直接訪問 官方文檔,從怎麼安裝React開始學習,也能夠看看 React 入門實例教程 這篇文章,筆者就是經過這篇文章入門的。node
言歸正傳,你能夠直接下載源碼直接使用,不用另外安裝,只需把這個庫拷貝到你的硬盤就好了。也能夠去官網下載,官方文檔已經寫得很清楚了。react
1. HTML模板git
使用 React 的網頁源碼,結構大體以下:github
<!DOCTYPE html> <html> <head> <script src="../build/react.js"></script> <script src="../build/react-dom.js"></script> <script src="../build/browser.min.js"></script> </head> <body> <div id="root"></div> <script type="text/babel"> // ** 代碼放這 ** </script> </body> </html>
上面代碼有兩個地方須要注意。首先,最後一個 <script>
標籤的 type
屬性爲 text/babel
。這是由於 React 獨有的 JSX 語法,跟 JavaScript 不兼容。凡是使用 JSX 的地方,都要加上 type="text/babel"
。web
其次,上面代碼一共用了三個庫: react.js
、react-dom.js
和 Browser.js
,它們必須首先加載。其中,react.js
是 React 的核心庫,react-dom.js
是提供與 DOM 相關的功能,Browser.js
的做用是將 JSX 語法轉爲 JavaScript 語法,這一步很消耗時間,實際上線的時候,應該將它放到服務器完成。算法
$ babel src --out-dir build
上面命令能夠將 src
子目錄的 js
文件進行語法轉換,轉碼後的文件所有放在 build
子目錄。api
2. ReactDOM.render()
ReactDOM.render 是 React 的最基本方法,用於將模板轉爲 HTML 語言,並插入指定的 DOM 節點。
ReactDOM.render( <h1>Hello,React!</h1>, document.getElementById('root') );
上面代碼將一個 h1
標題,插入 root
節點(查看 Demo
),運行結果以下:
3. JSX 語法
上一節的代碼, HTML 語言直接寫在 JavaScript 語言之中,不加任何引號,這就是 JSX 的語法,它容許 HTML 與 JavaScript 的混寫(查看 Demo
):
function tick() { const element = ( <div> <h1>Hello,React!</h1> <h2>It is {new Date().toLocaleTimeString()}.</h2> </div> ); ReactDOM.render( element, document.getElementById('root') ); } tick(); setInterval(tick,1000);
最終效果會顯示相關文字,並每秒更新本地時間:
再看一個 Demo :
var names = ['Alice','Emily','Kate','Luka']; const element = ( <div> { names.map(function (name) { return <h2>Hello,{name}!</h2> }) } </div> ); const root = document.getElementById('root'); ReactDOM.render( element, root );
上面代碼體現了 JSX 的基本語法規則:遇到 HTML 標籤(以 <
開頭),就用 HTML 規則解析;遇到代碼塊(以 {
開頭),就用 JavaScript 規則解析。上面代碼的運行結果以下:
JSX 容許直接在模板插入 JavaScript 變量。若是這個變量是一個數組,則會展開這個數組的全部成員(查看 Demo
):
var arr = [ <h1>Hello React!</h1>, <h2>React is awesome!</h2> ]; var root = document.getElementById('root'); ReactDOM.render( <div>{arr}</div>, root );
上面代碼的 arr
變量是一個數組,結果 JSX 會把它的全部成員,添加到模板,運行結果以下。
4. 組件
React 容許將代碼封裝成組件(component),而後像插入普通 HTML 標籤同樣,在網頁中插入這個組件。React.createClass 方法就用於生成一個組件類(查看 Demo
)
var HelloMessage = React.createClass({ render:function () { return <h1>Hello,{this.props.name}! {this.props.msg}</h1>; } }); var root = document.getElementById('root'); ReactDOM.render( <HelloMessage name="Luka" msg="Nice to meet you!"/>, root );
上面代碼中,變量 HelloMessage
就是一個組件類。模板插入 <HelloMessage />
時,會自動生成 HelloMessage
的一個實例(下文的"組件"都指組件類的實例)。全部組件類都必須有本身的 render
方法,用於輸出組件。
注意,組件類的第一個字母必須大寫,不然會報錯,好比HelloMessage
不能寫成helloMessage
。另外,組件類只能包含一個頂層標籤,不然也會報錯。
var HelloMessage = React.createClass({ render: function() { return <h1> Hello {this.props.name} </h1><p> some text </p>; } });
上面代碼會報錯,由於HelloMessage
組件包含了兩個頂層標籤:h1
和p
。
組件的用法與原生的 HTML 標籤徹底一致,能夠任意加入屬性,好比 <HelloMessage name="Luka">
,就是 HelloMessage
組件加入一個 name
屬性,值爲 Luka
。組件的屬性能夠在組件類的 this.props
對象上獲取,好比 name
屬性就能夠經過 this.props.name
讀取。上面代碼的運行結果以下:
添加組件屬性,有一個地方須要注意,就是 class
屬性須要寫成 className
,for
屬性須要寫成 htmlFor
,這是由於 class
和 for
是 JavaScript 的保留字。
5. this.props.children
this.props
對象的屬性與組件的屬性一一對應,可是有一個例外,就是 this.props.children
屬性。它表示組件的全部子節點(查看 Demo
)
var NotesList = React.createClass({ render:function () { return ( <ol> { React.Children.map(this.props.children,function (child) { return <li>{child}</li> }) } </ol> ); } }); var root = document.getElementById('root'); ReactDOM.render( <NotesList> <h1>Alice</h1> <h2>Kate</h2> <h3>Tom</h3> <h4>Luka</h4> </NotesList>, root );
上面代碼的 NoteList
組件有四個子節點,它們均可以經過 this.props.children
讀取,運行結果以下:
這裏須要注意, this.props.children
的值有三種可能:若是當前組件沒有子節點,它就是 undefined
;若是有一個子節點,數據類型是 object
;若是有多個子節點,數據類型就是 array
。因此,處理 this.props.children
的時候要當心。
React 提供一個工具方法 React.Children
來處理 this.props.children
。咱們能夠用 React.Children.map
來遍歷子節點,而不用擔憂 this.props.children
的數據類型是 undefined
仍是 object
。更多的 React.Children
的方法,請參考官方文檔。
6. PropTypes
組件的屬性能夠接受任意值,字符串、對象、函數等等均可以。有時,咱們須要一種機制,驗證別人使用組件時,提供的參數是否符合要求。
組件類的PropTypes
屬性,就是用來驗證組件實例的屬性是否符合要求(查看 Demo
)
var MyTitle = React.createClass({ propTypes: { title: React.PropTypes.string.isRequired, }, render: function() { return <h1> {this.props.title} </h1>; } });
上面的Mytitle
組件有一個title
屬性。PropTypes
告訴 React,這個 title
屬性是必須的,並且它的值必須是字符串。如今,咱們設置 title
屬性的值是一個數值。
var data = 123; ReactDOM.render( <MyTitle title={data} />, document.body );
這樣一來,title
屬性就通不過驗證了。控制檯會顯示一行錯誤信息。
更多的PropTypes
設置,能夠查看官方文檔。
此外,getDefaultProps
方法能夠用來設置組件屬性的默認值。
var MyTitle = React.createClass({ getDefaultProps : function () { return { title : 'Hello World' }; }, render: function() { return <h1> {this.props.title} </h1>; } }); ReactDOM.render( <MyTitle />, document.getElementById('root') );
7. 獲取真實的DOM節點
組件並非真實的 DOM 節點,而是存在於內存之中的一種數據結構,叫作虛擬 DOM (virtual DOM)。只有當它插入文檔之後,纔會變成真實的 DOM 。根據 React 的設計,全部的 DOM 變更,都先在虛擬 DOM 上發生,而後再將實際發生變更的部分,反映在真實 DOM上,這種算法叫作 DOM diff ,它能夠極大提升網頁的性能表現。
可是,有時須要從組件獲取真實 DOM 的節點,這時就要用到 ref
屬性(查看 Demo )
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> ); } }); var root = document.getElementById('root'); ReactDOM.render( <MyComponent />, root );
上面代碼中,組件 MyComponent
的子節點有一個文本輸入框,用於獲取用戶的輸入。這時就必須獲取真實的 DOM 節點,虛擬 DOM 是拿不到用戶輸入的。爲了作到這一點,文本輸入框必須有一個 ref
屬性,而後 this.refs.[refName]
就會返回這個真實的 DOM 節點。
須要注意的是,因爲 this.refs.[refName]
屬性獲取的是真實 DOM ,因此必須等到虛擬 DOM 插入文檔之後,才能使用這個屬性,不然會報錯。上面代碼中,經過爲組件指定 Click
事件的回調函數,確保了只有等到真實 DOM 發生 Click
事件以後,纔會讀取 this.refs.[refName]
屬性。
React 組件支持不少事件,除了 Click
事件之外,還有 KeyDown
、Copy
、Scroll
等,完整的事件清單請查看官方文檔。
8. this.state
組件免不了要與用戶互動,React 的一大創新,就是將組件當作是一個狀態機,一開始有一個初始狀態,而後用戶互動,致使狀態變化,從而觸發從新渲染 UI (查看 Demo
)
var LinkButton = 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> ); } }); var root = document.getElementById('root'); ReactDOM.render( <LinkButton />, root );
上面代碼是一個 LikeButton
組件,它的 getInitialState
方法用於定義初始狀態,也就是一個對象,這個對象能夠經過 this.state
屬性讀取。當用戶點擊組件,致使狀態變化,this.setState
方法就修改狀態值,每次修改之後,自動調用 this.render
方法,再次渲染組件。
因爲 this.props
和 this.state
都用於描述組件的特性,可能會產生混淆。一個簡單的區分方法是,this.props
表示那些一旦定義,就再也不改變的特性,而 this.state
是會隨着用戶互動而產生變化的特性。
9.表單
用戶在表單填入的內容,屬於用戶跟組件的互動,因此不能用 this.props
讀取(查看 Demo
)
var Input = React.createClass({ getInitialState:function () { return {value:'Hello!'} }, handleChange:function (event) { this.setState({value:event.target.value}); }, render:function () { var value = this.state.value; return ( <div> <input type="text" value={value} onChange={this.handleChange} /> <p>{value}</p> </div> ) } }); var root = document.getElementById('root'); ReactDOM.render( <Input/>, root );
上面代碼中,文本輸入框的值,不能用 this.props.value
讀取,而要定義一個 onChange
事件的回調函數,經過 event.target.value
讀取用戶輸入的值。
textarea
元素、select
元素、radio
元素都屬於這種狀況,更多介紹請參考官方文檔。
10. 組件的生命週期
組件的生命週期分紅三個狀態:
Mounting:已插入真實 DOM Updating:正在被從新渲染 Unmounting:已移出真實 DOM
React 爲每一個狀態都提供了兩種處理函數,will
函數在進入狀態以前調用,did
函數在進入狀態以後調用,三種狀態共計五種處理函數。
componentWillMount() componentDidMount() componentWillUpdate(object nextProps, object nextState) componentDidUpdate(object prevProps, object prevState) componentWillUnmount()
此外,React 還提供兩種特殊狀態的處理函數。
componentWillReceiveProps(object nextProps):已加載組件收到新的參數時調用 shouldComponentUpdate(object nextProps, object nextState):組件判斷是否從新渲染時調用
這些方法的詳細說明,能夠參考官方文檔。下面是一個例子(查看 Demo
)
var Hello = React.createClass({ getInitialState:function () { return { opacity:1.0, color:'#FF0000' } }, //已插入真實DOM後調用 //經過 componentDidMount 方法設置一個定時器,每隔100毫秒,就從新設置組件的透明度,從而引起從新渲染。 componentDidMount:function () { this.timer = setInterval(function () { var opacity = this.state.opacity; opacity -= 0.05; if(opacity < 0.1){ opacity = 1.0; } this.setState({ opacity:opacity }); }.bind(this),100) }, render:function () { return ( <div style={{opacity:this.state.opacity,color:this.state.color}}> <h1>Hello,{this.props.name}!</h1> </div> ); } }); var root = document.getElementById('root'); ReactDOM.render( <Hello name="Luka"/>, root );
上面代碼在hello
組件加載之後,經過 componentDidMount
方法設置一個定時器,每隔100毫秒,就從新設置組件的透明度,從而引起從新渲染。
另外,組件的style
屬性的設置方式也值得注意,不能寫成
style="opacity:{this.state.opacity};"
而要寫成
style={{opacity: this.state.opacity}}
這是由於 React 組件樣式是一個對象,因此第一重大括號表示這是 JavaScript 語法,第二重大括號表示樣式對象。
11. Ajax
組件的數據來源,一般是經過 Ajax 請求從服務器獲取,可使用 componentDidMount
方法設置 Ajax 請求,等到請求成功,再用 this.setState
方法從新渲染 UI (查看 Demo
)
var UserGist = React.createClass({ getInitialState:function () { return { name:'', website_url:'' }; }, componentDidMount:function () { $.get(this.props.source,function (data) { if(this.isMounted()){ this.setState({ name:$(data).find('name').text(), website_url:$(data).find('website_url').text() }); } }.bind(this)); }, render:function () { return( <div> {this.state.name}'s website url is <a href={this.state.website_url}>here</a>. </div> ); } }); ReactDOM.render( <UserGist source="http://www.ycdoit.com/api/Web4Luka.asmx/HelloWorld"/>, document.getElementById('root') );
上面代碼使用 jQuery 完成 Ajax 請求,這是爲了便於說明。顯示效果以下,點擊連接能夠打開對應的網址:
React 自己沒有任何依賴,徹底能夠不用jQuery,而使用其餘庫。
咱們甚至能夠把一個Promise對象傳入組件,請看Demo
ReactDOM.render( <RepoList promise={$.getJSON('https://api.github.com/search/repositories?q=javascript&sort=stars')}/>, document.getElementById('root') );
上面代碼從Github的API抓取數據,而後將Promise對象做爲屬性,傳給RepoList
組件。
若是Promise對象正在抓取數據(pending狀態),組件顯示"正在加載";若是Promise對象報錯(rejected狀態),組件顯示報錯信息;若是Promise對象抓取數據成功(fulfilled狀態),組件顯示獲取的數據。
var RepoList = React.createClass({ getInitialState:function () { return { loading:true, error:null, data:null }; }, componentDidMount(){ this.props.promise.then( value => this.setState({loading:false,data:value}), error => this.setState({loading:false,data:error}) ) }, render:function () { if(this.state.loading){ return <span>Loading...</span>; }else if(this.state.error!==null){ return <span>Error:{this.state.error.message}</span>; }else{ var repos = this.state.data.items; var repoList = repos.map(function (repo, index) { return ( <li key={index}><a href={repo.html_url}>{repo.name}</a> ({repo.stargazers_count} stars) <br />{repo.description}</li> ); }); return ( <main> <h1>Most Popular Javascript Projects in Github</h1> <ol> {repoList} </ol> </main> ); } } }); ReactDOM.render( <RepoList promise={$.getJSON('https://api.github.com/search/repositories?q=javascript&sort=stars')}/>, document.getElementById('root') );
源碼地址:https://github.com/YeXiaoChao/PluginsFromJS/tree/master/React