說到React,我從一年以前就開始試着瞭解而且看了相關的入門教程,並且還買過一本《React:引領將來的用戶界面開發框架 》拜讀。React的輕量組件化的思想及其virtual-dom的這種技術創新,也算是早就有了初步瞭解。一來沒有學的太深刻,二來後來在工做中和業餘項目中都沒有用到,所以慢慢的就更加生疏了。javascript
近期,由於我想把本身的開源項目wangEditor能放在React、angular和vuejs中使用。先從react開始,順手本身也重試一下React的基礎知識,順便再作一個小demo,體驗一下React寫程序的一些提倡的思路。通過幾天的回顧學習,我也寫了一個在React中集成wangEditor的簡單demo:http://www.kancloud.cn/wangfupeng/wangeditor2/129376php
不得不說一下,React風靡世界、功能強大、適應性強,可是入門起來至關簡單。反觀angularjs,學習成本就比較高,我還沒弄明白1.x呢,2.0已經出來了。縱然我很是努力,可是某些方面仍是擺脫不了out的命運(見笑...)。css
想入門React,首先你得有比較紮實的javascript語法基礎以及前端開發的基礎知識,不然我下面推薦的教程講的再好,你也咂摸不出啥滋味來。因此若是你是初學者,不要被如今前端這些琳琅滿目的框架、庫迷惑了眼睛,覺得學會了這個那個就好了——基礎不行學啥都白搭。html
閒話很少扯。前人栽樹後人乘涼,給你們推薦兩個我看過的很是好的React入門教程,一個文字一個視頻。前端
這兩篇教程的篇幅都不長 ,閱讀加練習的話,兩個晚上(正常下班吃完飯以後的剩餘時間)絕對能搞定的。固然你若是具有程序員優質的熬夜技能,一夜搞定也說不定啊,創造奇蹟的同時照顧一下身體,哈哈。看完這兩篇教程,你能基本瞭解react的設計思想,技術特色,使用的語法和技巧。作個hello word什麼的,徹底沒啥問題的。vue
記得幾年前上大學乃至剛畢業那會兒,不管是學java仍是php仍是.net的,會了語法、會寫個hello world確定不能算是入門的。當時跟hello world齊名還有一個東西叫作『留言板』。師生之間常常有這樣的對話。java
上述的『留言板』也隨着幾年以前流行的bbs、論壇、校內網等沒幾年就河了西了(《大宅門》學的),目前用來作demo的通常都是todolist,例如backbone的官方demo就是一個todolist。react
不管是『留言板』仍是『todolist』,咱們須要用它來表達的就是——咱們如何經過這項技術去實現基本的『增刪改查』 這種能力,由於一個系統其餘全部的業務邏輯操做,都是『增刪改查』這幾個功能的拼接。因此,咱們在剛剛接觸一個新東西的時候,就用它來作一個簡單的todolist吧。git
作出來大約是這樣子的,很簡單很醜,too 羊 too 森破 sometime native 。不過不要緊,雖然它很醜,可是很溫柔啊。咱們只是拋開了其餘內容,專一於這項技術實現的自己而已。若是你想漂亮一點,本身寫一個css樣式嘍。程序員
下面我將一步一步講解如何使用React來製做出一個簡單的todolist,不過仍是須要你耐心把文章讀完,我也儘可能寫的可讀性強一些,不至於太乏味。
React最大的賣點是輕量組件化。咱們分析一下以上截圖中的頁面,若是要分組件的話,咱們大約能夠分紅一個總組件和兩個子組件。一個輸入內容的組件,一個顯示內容列表(帶刪除功能)的組件,外面再用一個總組件將兩個子組件包括起來。
所以,咱們的代碼的總體結構大約是這麼寫的:
1 // TodoList 組件是一個總體的組件,最終的React渲染也將只渲染這一個組件 2 // 該組件用於將『新增』和『列表』兩個組件集成起來 3 var TodoList = React.createClass({ 4 render: function () { 5 return ( 6 <div> 7 <TypeNew /> 8 <ListTodo /> 9 </div> 10 ); 11 } 12 }); 13 14 // TypeNew 組件用於新增數據, 15 var TypeNew = React.createClass({ 16 render: function () { 17 return ( 18 <form> 19 <input type="text" placeholder="typing a newthing todo" autoComplete="off" /> 20 </form> 21 ); 22 } 23 }); 24 25 // ListTodo 組件用於展現列表,並能夠刪除某一項內容, 26 var ListTodo = React.createClass({ 27 render: function () { 28 return ( 29 <ul id="todo-list"> 30 {/* 其中顯示數據列表 */} 31 </ul> 32 ); 33 } 34 }); 35 36 // 將 TodoList 組件渲染到頁面 37 React.render(<TodoList />, document.getElementById('container'));
下面,咱們要把todolist的數據,顯示到列表中,而且每一個數據項後面都顯示一個『刪除』按鈕,就像這樣:
既然是展現數據,首先要考慮數據存儲在哪裏,來自於哪裏。如今這裏放一句話——React提倡全部的數據都是由父組件來管理,經過props的形式傳遞給子組件來處理——先記住,接下來再解釋這句話。
上文提到,作一個todolist頁面須要一個父組件,兩個子組件。父組件固然就是todolist的『總指揮』,兩個子組件分別用來add和show、delete。用通俗的方式講來,父組件就是領導,兩個子組件就是協助領導開展工做的,一切的資源和調動資源的權利,都在領導層級,子組件配合領導工做,須要資源或者調動資源,只能申請領導的批准。
這麼說來就明白了吧。數據徹底由父組件來管理和控制,子組件用來顯示、操做數據,得通過父組件的批准,即——父組件經過props的形式將數據傳遞給子組件,子組件拿到父組件傳遞過來的數據,再進行展現。
另外,根據React開發的規範,組件內部的數據由state控制,外部對內部傳遞數據時使用 props 。這麼看來,針對父組件來講,要存儲todolist的數據,那就是內部信息(自己就是本身可控的資源,而不是『領導』控制的資源),用state來存儲便可。而父組件要將todolist數據傳遞給子組件,對子組件來講,那就是傳遞進來的外部信息(是『領導』的資源,交付給你來處理),須要使用props。
好了,咱們再修改一下代碼,用代碼表述一下這個問題:
1 // TodoList 組件是一個總體的組件,最終的React渲染也將只渲染這一個組件 2 // 該組件用於將『新增』和『列表』兩個組件集成起來 3 var TodoList = React.createClass({ 4 // 初始化數據,todolist的數據由state來控制 5 getInitialState: function () { 6 return { 7 todolist: [] 8 }; 9 }, 10 render: function () { 11 return ( 12 <div> 13 <TypeNew /> 14 {/* 15 集成 ListTodo 組件 16 todo - 將todolist的數據傳入到組件,用於組件展現數據 17 */} 18 <ListTodo todo={this.state.todolist} /> 19 </div> 20 ); 21 } 22 }); 23 24 // TypeNew 組件用於新增數據, 25 var TypeNew = React.createClass({ 26 // 此處省略 ... 字 27 }); 28 29 // ListTodo 組件用於展現列表,並能夠刪除某一項內容, 30 var ListTodo = React.createClass({ 31 render: function () { 32 return ( 33 <ul id="todo-list"> 34 { 35 // this.props.todo 獲取父組件傳遞過來的數據 36 // {/* 遍歷數據 */} 37 this.props.todo.map(function (item, i) { 38 return ( 39 <li> 40 <label>{item}</label> 41 <button>delete</button> 42 </li> 43 ); 44 }) 45 } 46 </ul> 47 ); 48 } 49 }); 50 51 // 將 TodoList 組件渲染到頁面 52 React.render(<TodoList />, document.getElementById('container'));
剛纔都把數據展現講完了,可是想展現一下,目前尚未數據呢,那就新增一個吧。以下圖:
根據剛纔的拐彎抹角、高談闊論、旁徵博引的那幾句話,咱們知道,子組件獲得數據後,就須要將新數據添加到todolist的數據中。而todolist的數據是由父組件來管理的,子組件不能說改就改呀,得申請父組件的容許和贊成呀。所以,咱們須要讓父組件開放一個能夠修改數據的接口,而後將這個接口做爲props傳遞給子組件,讓其能修改數據。
另外,子組件調用父組件的接口對todolist數據進行修改了以後,至關於修改了React對象的state數據,此時就會觸發React的自動更新(就是經過virtual-dom對比,而後更新真實的dom那一套),React會將UI實時隨着數據更新,就不用咱們操心了,這也是React比較強大的地方之一。
所以,代碼將改成:
1 // TodoList 組件是一個總體的組件,最終的React渲染也將只渲染這一個組件 2 // 該組件用於將『新增』和『列表』兩個組件集成起來 3 var TodoList = React.createClass({ 4 // 初始化數據,todolist的數據由state來控制 5 getInitialState: function () { 6 return { 7 todolist: [] 8 }; 9 }, 10 // 接收一個傳入的數據,並將它實時更新到組件的 state 中,以便組件根據數據從新render 11 // 只要改變了 state ,react自動執行 reader 計算 12 handleChange: function (rows) { 13 this.setState({ 14 todolist: rows 15 }); 16 }, 17 render: function () { 18 return ( 19 <div> 20 {/* 21 集成 TypeNews 組件,傳入兩個屬性 onAdd 和 todo 22 todo - 將todolist的數據傳入到組件,當新增時,更新todolist數據 23 onAdd - 將 handleChange 函數傳入到組件,新增時,用它來處理最新的todolist數據 24 */} 25 <TypeNew onAdd={this.handleChange} todo={this.state.todolist} /> 26 {/* 27 集成 ListTodo 組件 28 todo - 將todolist的數據傳入到組件,用於組件展現數據 29 */} 30 <ListTodo todo={this.state.todolist} /> 31 </div> 32 ); 33 } 34 }); 35 36 // TypeNew 組件用於新增數據,它須要 todo 和 onAdd 兩個屬性,上文已經提到過 37 // 基本邏輯是:當從 input 中獲取數據時,將新數據 push 到todo中, 38 // 而後使用 onAdd 調用 TodoList 的 handleChange 來更新state,而後react自動render 39 var TypeNew = React.createClass({ 40 handleAdd: function (e) { 41 e.preventDefault(); 42 // 經過 refs 獲取dom元素,而後獲取輸入的內容 43 var inputDom = this.refs.inputnew.getDOMNode(); 44 var newthing = inputDom.value.trim(); 45 // 獲取傳入的todolist數據 46 var rows = this.props.todo; 47 if (newthing !== '') { 48 // 更新數據,並使用 onAdd 更新到 TodoList 組件的 state 中 49 rows.push(newthing); 50 this.props.onAdd(rows); 51 } 52 inputDom.value = ''; 53 }, 54 render: function () { 55 return ( 56 // form submit 時,觸發 handleAdd 事件 57 <form onSubmit={this.handleAdd}> 58 <input type="text" ref="inputnew" id="todo-new" placeholder="typing a newthing todo" autoComplete="off" /> 59 </form> 60 ); 61 } 62 }); 63 64 // ListTodo 組件用於展現列表,並能夠刪除某一項內容, 65 var ListTodo = React.createClass({ 66 render: function () { 67 return ( 68 <ul id="todo-list"> 69 { 70 // this.props.todo 獲取父組件傳遞過來的數據 71 // {/* 遍歷數據 */} 72 this.props.todo.map(function (item, i) { 73 return ( 74 <li> 75 <label>{item}</label> 76 <button>delete</button> 77 </li> 78 ); 79 }) 80 } 81 </ul> 82 ); 83 } 84 }); 85 86 // 將 TodoList 組件渲染到頁面 87 React.render(<TodoList />, document.getElementById('container'));
刪除數據和新增數據,邏輯上是同樣的,都是須要父組件提供一個修改數據的接口,經過props形式傳遞給子組件,而後讓子組件來調用。就再也不贅述了,直接上代碼,注意看註釋:
1 // TodoList 組件是一個總體的組件,最終的React渲染也將只渲染這一個組件 2 // 該組件用於將『新增』和『列表』兩個組件集成起來,而且存儲 todolist 的數據 3 var TodoList = React.createClass({ 4 // 初始化數據 5 getInitialState: function () { 6 return { 7 todolist: [] 8 }; 9 }, 10 // 接收一個傳入的數據,並將它實時更新到組件的 state 中,以便組件根據數據從新render 11 // 只要改變了 state ,react自動執行 reader 計算 12 handleChange: function (rows) { 13 this.setState({ 14 todolist: rows 15 }); 16 }, 17 render: function () { 18 return ( 19 <div> 20 {/* 21 集成 TypeNews 組件,傳入兩個屬性 onAdd 和 todo 22 todo - 將todolist的數據傳入到組件,當新增時,更新todolist數據 23 onAdd - 將 handleChange 函數傳入到組件,新增時,用它來處理最新的todolist數據 24 */} 25 <TypeNew onAdd={this.handleChange} todo={this.state.todolist} /> 26 {/* 27 集成 ListTodo 組件,傳入兩個屬性 onDel 和 todo 28 todo - 將todolist的數據傳入到組件,當刪除時,更新todolist數據 29 onDel - 將 handleChange 函數傳入到組件,刪除時,用它來處理最新的todolist數據 30 */} 31 <ListTodo onDel={this.handleChange} todo={this.state.todolist} /> 32 </div> 33 ); 34 } 35 }); 36 37 // TypeNew 組件用於新增數據,它須要 todo 和 onAdd 兩個屬性,上文已經提到過 38 // 基本邏輯是:當從 input 中獲取數據時,將新數據 push 到todo中, 39 // 而後使用 onAdd 調用 TodoList 的 handleChange 來更新state,而後react自動render 40 var TypeNew = React.createClass({ 41 handleAdd: function (e) { 42 e.preventDefault(); 43 // 經過 refs 獲取dom元素,而後獲取輸入的內容 44 var inputDom = this.refs.inputnew.getDOMNode(); 45 var newthing = inputDom.value.trim(); 46 // 獲取傳入的todolist數據 47 var rows = this.props.todo; 48 if (newthing !== '') { 49 // 更新數據,並使用 onAdd 更新到 TodoList 組件的 state 中 50 rows.push(newthing); 51 this.props.onAdd(rows); 52 } 53 inputDom.value = ''; 54 }, 55 render: function () { 56 return ( 57 // form submit 時,觸發 handleAdd 事件 58 <form onSubmit={this.handleAdd}> 59 <input type="text" ref="inputnew" id="todo-new" placeholder="typing a newthing todo" autoComplete="off" /> 60 </form> 61 ); 62 } 63 }); 64 65 // ListTodo 組件用於展現列表,並能夠刪除某一項內容,它有 noDel todo 兩個屬性,上文已經提到過 66 // 它的基本邏輯是:遍歷 todo 的內容,生成數據列表和刪除按鈕 67 // 對某一項執行刪除時,想將 todo 中的數據刪除, 68 // 而後經過 onDel 事件調用 TodoList 的 handleChange 來更新state,而後react自動render 69 var ListTodo = React.createClass({ 70 handleDel: function (e) { 71 var delIndex = e.target.getAttribute('data-key'); 72 // 更新數據,並使用 onDel 更新到 TodoList 的 state 中,以便 React自動render 73 this.props.todo.splice(delIndex, 1); 74 this.props.onDel(this.props.todo); 75 }, 76 render: function () { 77 return ( 78 <ul id="todo-list"> 79 { 80 // {/* 遍歷數據 */} 81 this.props.todo.map(function (item, i) { 82 return ( 83 <li> 84 <label>{item}</label> 85 <button className="destroy" onClick={this.handleDel} data-key={i}>delete</button> 86 </li> 87 ); 88 }.bind(this)) // {/* 綁定函數的執行this - 以便 this.handleDel */} 89 } 90 </ul> 91 ); 92 } 93 }); 94 95 // 將 TodoList 組件渲染到頁面 96 React.render(<TodoList />, document.getElementById('container'));
入門React的基本語法和使用比較簡單,可是想要了解它的工做過程和基本的設計思想,仍是須要一點時間的。接下來,在大型系統中使用React確定又須要更多的時間,你可能還會遇到不少坑,等着你去填。
可是不管如今用仍是不用,我們都不能落伍,該學的仍是得掌握一些比較好。你們共勉。
最後,此文章參考了 http://react-china.org/t/todolist/1075 感謝本文做者
-------------------------------------------------------------------------------------------------------------
歡迎關注個人教程:
《使用grunt搭建全自動web前端開發環境》《json2.js源碼解讀視頻》
《深刻理解javascript原型和閉包系列》《css知多少》《微軟petshop4.0源碼解讀視頻》
------------------------------------------------------------------------------------------------------------
wangEditor-mobile,適用於手機的富文本編輯器
-------------------------------------------------------------------------------------------------------------