原文寫於 2015-04-15 https://github.com/kuitos/kuitos.github.io/issues/21javascript
要說2015年前端屆最備受矚目的技術是啥,固然非ReactJs莫屬。做爲一個只關注最前沿前端技術的系列,天然少不了關於它的介紹。html
React最初來自Facebook內部的廣告系統項目,項目實施過程當中前端開發遇到了巨大挑戰,代碼變得愈來愈臃腫且混亂不堪,難以維護。因而痛定思痛,他們決定拋開不少所謂的「最佳實踐」,從新思考前端界面的構建方式,因而就有了React。前端
React的設計依託於Facebook另外一個叫作FLUX的項目,FLUX是一個爲了解決Facebook在MVC應用中碰到的工程性問題而生的設計模式,主要思路是單向數據流。解析 Facebook 的 Flux 應用架構java
React是MVC中薄薄的一層V,它只關注表現層,對組件化開發有很大的裨益。node
virtual dom react中的組件跟頁面真實dom之間會有一層virtual dom(虛擬dom),virtual dom是內存中的javascript對象,它具備與真實dom一致的樹狀結構。開發者每次試圖更新view,react都會從新構建virtual dom樹,而後將其與上一次virtual dom樹做對比,依靠react強勁的核心算法dom diff找出真正發生變動的節點,最後映射到真實dom上,這也是react號稱性能高效的祕密所在。依賴於virtual dom,對React而言,每一次界面的更新都是總體更新,而不是層疊式更新(即一個複雜的,各個UI之間可能存在互相依賴的時候,每一次獨立的更新可能會引起其餘UI的變化,假如咱們的目的是更新C的數據,邏輯流極可能是這樣的 A -->B-->C-->A-->B–>C,這種狀況下中間狀態的DOM操做就是極大的浪費)。react
單向數據流 flux架構下的數據流呈現出一種單向、閉環的流動路線,使得一切行爲變的可預測,也能更好的定位錯誤發生點。react官方的賣點之一就是 友好的錯誤提示(這是在針對angular麼哈哈)git
每一個組件都是狀態機 react認爲組件的數據模型是不可變的,組件的屬性不該該被修改。組件關注的只應該是狀態,不一樣的狀態呈現不一樣的表現形式。每一個狀態下的組件都是一個virtual dom對象,這樣react就能直接經過等號對比對象地址判斷組件是否被修改從而是否須要更新dom,這也是其能提升性能的緣由之一(空間換時間)。github
組件 一切都是組件 react倡導開發者將view切分紅一個個組件從而達到鬆耦合及重用的目的。開發者構建頁面只須要排列組合就好了。算法
immutable object React提倡使用只讀數據來創建數據模型,每次更新都是new object,這也是dom diff 性能強勁的密碼所在(===便可判斷兩個對象是否相等,而不須要深度遍歷)。參考資料 immutable.jsnpm
JSX 不是在js裏面寫html,jsx是xml的javascript表示法。
說了這麼多理論性的東西,仍是直接來上代碼吧
首先你須要reactjs的開發環境。
bower install react
腳本中引入react,因爲咱們須要使用jsx語法提升開發效率,因此還須要引入能講jsx轉化爲javascript的庫
不過這樣JSXTransformer每次都會在app打開的時候作轉換工做,並不適合生產環境,轉換工做應該放在服務端進行,藉助jsx工具
npm install -g react-tools jsx --watch src/ build/
而後頁面依賴改爲這樣
node插件會在你開發的時候自動將源碼轉成javascript文件到指定目錄
// Hello World React.render( <h1>Hello, world!</h1>, document.getElementById('example') );
React.render() 將模版轉換成html並插入到指定節點 參見上文的hello world示例
React解析引擎的規則就是遇到<符號就以jsx語法解析,遇到{就以javascript語法解析。好比這樣
var array = [ <h1>Example 2</h1>, <h2>Hello World</h2> ]; React.render( <div>{array}</div>, document.getElementById("example2") );
經過查看轉換後的代碼,咱們能夠看到他摘下面具後長這樣
var array = [ React.createElement("h1", null, "Example 2"), React.createElement("h2", null, "Hello World") ]; React.render( React.createElement("div", null, array), document.getElementById("example2") );
如何建立組件
var HelloWorldComponent = React.createClass({ render: function () { return <div>React Component {this.props.author}</div>; } }); React.render( <HelloWorldComponent author="Kuitos"/>, document.getElementById("hello") );
經過React.createClass能夠建立一個關聯了虛擬dom的組件對象,每次組件數據更新便會調用組件的 render 方法從新渲染dom。
組件對象的props屬性
上面一個例子咱們看到在組件render方法中咱們能夠經過this.props.xx的方式拿到組件上關聯的屬性。另外須要額外提到的是,this.props有一個特殊屬性children,它指向組件的子節點集合,like this
var List = React.createClass({ render: function () { return ( <ol> { this.props.children.map(function (child) { return <li>{child}</li> }) } </ol> ); } }); React.render( <List> <a href="#">百度</a> <a href="#">谷歌</a> </List>, document.getElementById("example3") );
頁面渲染的結果就是一個 ol 列表中還有兩個li,每一個li中包含一個超連接。經過這裏咱們也能夠看出,在jsx中{}是會getValue的
獲取真實dom React.findDOMNode()
var counter = 0; var Button = React.createClass({ handleClick: function () { React.findDOMNode(this.refs.input).focus(); }, render: function () { return ( <div> <input type="text" ref="input"/> <input type="button" value="counter" onClick={this.handleClick}/> </div> ); } }); React.render( <Button />, document.getElementById("button") );
組件狀態 this.state
var Toggle = React.createClass({ getInitialState: function () { return {liked: false}; }, handleClick: function (event) { this.setState({liked: !this.state.liked}); }, render: function () { var text = this.state.liked ? "like" : "unlike"; return ( <p onClick={this.handleClick}> U {text} this. </p> ); } }); React.render( <Toggle />, document.getElementById("button1") );
用React的方式實現angular中雙向綁定的效果
var Input = React.createClass({ getInitialState: function () { return {value: "Kuitos"}; }, handleChange: function (event) { this.setState({value: event.target.value}); }, render: function () { var value = this.state.value; return ( <div> <p>{value}</p> <input type="text" value={value} onChange={this.handleChange}/> </div> ); } }); React.render( <Input/>, document.getElementById("inputDataBind") );
virtual dom狀態變動回調
組件生命週期分爲三個狀態:
Mouting: 已插入真實 DOM
Updating: 正在被從新渲染
Unmounting: 已移出真實 DOM
React爲每一個狀態都提供相應的pre跟post處理函數。只不過React的命名是will(pre 進入狀態以前)跟did(post 進入狀態以後)。
componentWillMount()
componentDidMount()
componentWillUpdate(Object nextProps, Object nextState)
componentDidUpdate(Object prevProps, Object prevState)
componentWillUnmount()
咱們這樣寫
var Input = React.createClass({ getInitialState: function () { return {firstName: "Kuitos", lastName: "Lau"}; }, handleChange: function (event) { this.setState({firstName: event.target.value}); }, componentWillMount: function () { console.log("dom will be insert", this.state.firstName); }, componentDidMount: function () { console.log("dom had be insert", this.state.firstName); }, componentWillUpdate: function (nextProps, nextState) { console.log("dom will be update", nextProps, nextState); }, componentDidUpdate: function (prevProps, prevState) { console.log("dom had be update", prevProps, prevState); }, render: function () { var state = this.state; return ( <div> <p>{state.firstName} {state.lastName}</p> <input type="text" value={state.firstName} author={state.firstName} onChange={this.handleChange}/> </div> ); } }); React.render( <Input/>, document.getElementById("inputDataBind") );
打印的順序依次是,dom will be update , dom had be update
當input輸入時 dom will be update , dom had be update
react的基本知識就介紹到這裏,後續咱們會繼續介紹react在實戰項目中的應用及react native在移動端的表現力。